Cast Int64 values to int, float in statistics

Currently statistics requests fail with type errors.
It causes by the fact that pymongo returns bson.Int64
instead of float or int for big nums. It affects a `cpu`
meter usually.

Change-Id: I744a9f79a4bbc3b2ecdd73c126b0859f3f8a733c
Closes-bug: #1532661
(cherry picked from commit 1d73a6f12f)
This commit is contained in:
Ilya Tyaptin 2016-03-03 20:12:06 +03:00 committed by gordon chung
parent 098ae2805a
commit af3cb7b524
3 changed files with 58 additions and 9 deletions

View File

@ -623,9 +623,10 @@ class Connection(pymongo_base.Connection):
def _stats_result_aggregates(self, result, aggregate):
stats_args = {}
for attr in Connection.STANDARD_AGGREGATES.keys():
for attr, func in Connection.STANDARD_AGGREGATES.items():
if attr in result:
stats_args[attr] = result[attr]
stats_args.update(func.finalize(result,
version_array=self.version))
if aggregate:
stats_args['aggregate'] = {}

View File

@ -48,7 +48,8 @@ OP_SIGN = {'lt': '$lt', 'le': '$lte', 'ne': '$ne', 'gt': '$gt', 'ge': '$gte'}
MINIMUM_COMPATIBLE_MONGODB_VERSION = [2, 4]
COMPLETE_AGGREGATE_COMPATIBLE_VERSION = [2, 6]
FINALIZE_AGGREGATION_LAMBDA = lambda result, param=None: float(result)
FINALIZE_FLOAT_LAMBDA = lambda result, param=None: float(result)
FINALIZE_INT_LAMBDA = lambda result, param=None: int(result)
CARDINALITY_VALIDATION = (lambda name, param: param in ['resource_id',
'user_id',
'project_id',
@ -525,7 +526,7 @@ class AggregationFields(object):
finalize=None,
parametrized=False,
validate=None):
self._finalize = finalize or FINALIZE_AGGREGATION_LAMBDA
self._finalize = finalize or FINALIZE_FLOAT_LAMBDA
self.group = lambda *args: group(*args) if parametrized else group
self.project = (lambda *args: project(*args)
if parametrized else project)
@ -576,23 +577,28 @@ class Aggregation(object):
SUM_AGGREGATION = Aggregation(
"sum", AggregationFields(MINIMUM_COMPATIBLE_MONGODB_VERSION,
{"sum": {"$sum": "$counter_volume"}},
{"sum": "$sum"}))
{"sum": "$sum"},
))
AVG_AGGREGATION = Aggregation(
"avg", AggregationFields(MINIMUM_COMPATIBLE_MONGODB_VERSION,
{"avg": {"$avg": "$counter_volume"}},
{"avg": "$avg"}))
{"avg": "$avg"},
))
MIN_AGGREGATION = Aggregation(
"min", AggregationFields(MINIMUM_COMPATIBLE_MONGODB_VERSION,
{"min": {"$min": "$counter_volume"}},
{"min": "$min"}))
{"min": "$min"},
))
MAX_AGGREGATION = Aggregation(
"max", AggregationFields(MINIMUM_COMPATIBLE_MONGODB_VERSION,
{"max": {"$max": "$counter_volume"}},
{"max": "$max"}))
{"max": "$max"},
))
COUNT_AGGREGATION = Aggregation(
"count", AggregationFields(MINIMUM_COMPATIBLE_MONGODB_VERSION,
{"count": {"$sum": 1}},
{"count": "$count"}))
{"count": "$count"},
FINALIZE_INT_LAMBDA))
STDDEV_AGGREGATION = Aggregation(
"stddev",
AggregationFields(MINIMUM_COMPATIBLE_MONGODB_VERSION,

View File

@ -1659,3 +1659,45 @@ class TestUnparameterizedAggregates(v2.FunctionalTest,
places=4)
for a in standard_aggregates:
self.assertNotIn(a, r)
@tests_db.run_with('mongodb')
class TestBigValueStatistics(v2.FunctionalTest):
PATH = '/meters/volume.size/statistics'
def setUp(self):
super(TestBigValueStatistics, self).setUp()
for i in range(0, 3):
s = sample.Sample(
'volume.size',
'gauge',
'GiB',
(i + 1) * (10 ** 12),
'user-id',
'project1',
'resource-id',
timestamp=datetime.datetime(2012, 9, 25, 10 + i, 30 + i),
resource_metadata={'display_name': 'test-volume',
'tag': 'self.sample',
},
source='source1',
)
msg = utils.meter_message_from_counter(
s, self.CONF.publisher.telemetry_secret,
)
self.conn.record_metering_data(msg)
def test_big_value_statistics(self):
data = self.get_json(self.PATH)
expected_values = {'count': 3,
'min': 10 ** 12,
'max': 3 * 10 ** 12,
'sum': 6 * 10 ** 12,
'avg': 2 * 10 ** 12}
self.assertEqual(1, len(data))
for d in data:
for name, expected_value in expected_values.items():
self.assertIn(name, d)
self.assertEqual(expected_value, d[name])