Move SampleContainer to collectd_ceilometer/common

SampleContainer was duplicated in ceilometer/ and gnocchi/

- Moved SampleContainer to collectd_ceilometer/common
- Added unit tests for SampleContainer

Change-Id: Id394c6b489d69840ff5de1eb07f1a4b357d3bb22
This commit is contained in:
Emma Foley 2017-03-24 17:10:47 +00:00
parent e2ce9e8ffd
commit a3effa6023
4 changed files with 132 additions and 78 deletions

View File

@ -16,12 +16,11 @@
from __future__ import unicode_literals
from collectd_ceilometer.ceilometer import sender as ceilometer_sender
from collections import defaultdict
from collectd_ceilometer.common.meters.storage import SampleContainer
from collections import namedtuple
import json
import logging
import six
import threading
import time
LOGGER = logging.getLogger(__name__)
@ -46,43 +45,6 @@ class Sample(namedtuple('Sample', ['value', 'timestamp', 'meta',
}
class SampleContainer(object):
"""Sample storage"""
def __init__(self):
self._lock = threading.Lock()
self._data = defaultdict(list)
def add(self, key, samples, limit):
"""Store list of samples under the key
Store the list of samples under the given key. If numer of stored
samples is greater than the given limit, all the samples are returned
and the stored samples are dropped. Otherwise None is returned.
@param key key of the samples
@param samples list of samples
@param limit sample list limit
"""
with self._lock:
current = self._data[key]
current += samples
if len(current) >= limit:
self._data[key] = []
return current
return None
def reset(self):
"""Reset stored samples
Returns all samples and removes them from the container.
"""
with self._lock:
retval = self._data
self._data = defaultdict(list)
return retval
class Writer(object):
"""Data collector"""

View File

@ -15,7 +15,9 @@
from __future__ import unicode_literals
from collections import defaultdict
import six
import threading
from collectd_ceilometer.common.meters.base import Meter
from collectd_ceilometer.common.meters.libvirt import LibvirtMeter
@ -41,3 +43,40 @@ class MeterStorage(object):
"""Get meter for the collectd plugin"""
# return specialized meter class for collectd plugin or default Meter
return self._meters.get(plugin, self._default)
class SampleContainer(object):
"""Temporary storage for collectd samples"""
def __init__(self):
self._lock = threading.Lock()
self._data = defaultdict(list)
def add(self, key, samples, limit):
"""Store list of samples under the key
Store the list of samples under the given key. If the number of stored
samples is greater than the given limit, all the samples are returned
and the stored samples are dropped. Otherwise None is returned.
@param key key of the samples
@param samples list of samples
@param limit sample list limit
"""
with self._lock:
current = self._data[key]
current += samples
if len(current) >= limit:
self._data[key] = []
return current
return None
def reset(self):
"""Reset stored samples
Returns all samples and removes them from the container.
"""
with self._lock:
retval = self._data
self._data = defaultdict(list)
return retval

View File

@ -15,14 +15,13 @@
from __future__ import unicode_literals
from collectd_ceilometer.common.meters.storage import SampleContainer
from collectd_ceilometer.gnocchi import sender as gnocchi_sender
from collections import defaultdict
from collections import namedtuple
import datetime
import json
import logging
import six
import threading
LOGGER = logging.getLogger(__name__)
@ -39,43 +38,6 @@ class Sample(namedtuple('Sample', ['value', 'timestamp', 'meta',
}
class SampleContainer(object):
"""Sample storage"""
def __init__(self):
self._lock = threading.Lock()
self._data = defaultdict(list)
def add(self, key, samples, limit):
"""Store list of samples under the key
Store the list of samples under the given key. If numer of stored
samples is greater than the given limit, all the samples are returned
and the stored samples are dropped. Otherwise None is returned.
@param key key of the samples
@param samples list of samples
@param limit sample list limit
"""
with self._lock:
current = self._data[key]
current += samples
if len(current) >= limit:
self._data[key] = []
return current
return None
def reset(self):
"""Reset stored samples
Returns all samples and removes them from the container.
"""
with self._lock:
retval = self._data
self._data = defaultdict(list)
return retval
class Writer(object):
"""Data collector"""

View File

@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
# Copyright 2010-2011 OpenStack Foundation
# Copyright (c) 2015 Intel Corporation.
#
# 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.
"""Plugin tests"""
from __future__ import unicode_literals
from collectd_ceilometer.common.meters.storage import SampleContainer
import unittest
from collections import defaultdict
class TestSampleContainer(unittest.TestCase):
"""Test the common.meters.storage.SampleContainer class"""
def setUp(self):
super(TestSampleContainer, self).setUp()
self.container = SampleContainer()
def test_sample_container_init(self):
"""Test creating the SampleContainer
Set-up: create a container
Test: Container is empty
Expected behaviour: container is an empty dict of lists
"""
self.assertEqual({}, self.container._data)
def test_sample_container_add(self):
"""Test adding an element to SampleContainer
Set-up: create empty SampleContainer
Test: add an element to the SampleContainer
Expected behaviour: _data contains the added elements
"""
retval = self.container.add("key1", ["value1"], 5)
self.assertEqual(retval, None)
self.assertEqual(["value1", ], self.container._data["key1"])
def test_sample_container_add_exceeds_limit(self):
"""Test adding an element to the Container so len > limit.
Set-up: len(SampleContainer._data ) < limit;
Test: Add items to the container so len() > limit
Expected behaviour: SampleContainer._data[key] is empty and add()
returns a list of samples of length limit
"""
self.assertEqual(self.container._data, defaultdict(list))
retval = self.container.add("key1", ["1", "2", "3", ], 2)
self.assertEqual(retval, ["1", "2", "3", ])
self.assertEqual([], self.container._data["key1"])
def test_sample_container_reset(self):
"""Test resetting the contents of a meter entry in SampleContainer
Set-up: add some entries to the container (two meters)
action: call container.reset
Expected behaviour: the container will be equivalent to a default dict
and reset returns the stored data
"""
expected = {"key1": ["one", "two", "three", ],
"key2": ["1", "2", "3", ]}
self.container.add("key1", expected["key1"], 42)
self.container.add("key2", expected["key2"], 42)
self.assertEqual(expected, self.container._data)
retval = self.container.reset()
self.assertEqual(expected, retval)
self.assertEqual({}, self.container._data)