gnocchi/test_{sender,writer): Add some missing tests

A number of unittests were added to cover existing functionality.
* gnocchi/test_sender.py
  * test_send
  * test_send_error_404
  * test_on_authenticated
  * test_create_request_url
  * test_handle_http_error
  * test_handle_http_error_404
* gnocchi/test_writer.py
  * test_write
  * test_write_metric_none
  * test_send_data

Change-Id: I81f84c60761667d714a14da9ae8a80fdf59de461
This commit is contained in:
Emma Foley 2017-07-21 14:33:31 +00:00
parent b5cb3b4158
commit 51ad38a2c3
2 changed files with 262 additions and 0 deletions

View File

@ -17,6 +17,8 @@
"""Plugin tests"""
import mock
import requests
import unittest
from collectd_openstack.gnocchi import sender as gnocchi_sender
@ -24,5 +26,153 @@ from collectd_openstack.gnocchi import sender as gnocchi_sender
class TestGnocchiSender(unittest.TestCase):
"""Test the sender class."""
def setUp(self):
self.sender = gnocchi_sender.Sender()
self.sender._url_base = \
"http://my-endpoint/v1/metric/%s/measures"
def test_init(self):
"""Make sure the right things are initialised.
Set-up: None
Test: Create instance of sender
Expected behaviour:
* sender instance has an empty dict of metric_id mappings
"""
self.assertEqual(self.sender._meter_ids,
{})
@mock.patch.object(gnocchi_sender.Sender, '_create_request_url')
@mock.patch.object(gnocchi_sender.Sender, '_perform_request')
def test_send(self, sender_perform_request, sender_create_request_url):
"""Test send() in normal circumstances.
Set-up: Define metername, payload and **kwargs
Test: call send with some data
Expected behaviour:
* _perform_request is called with an unchanged payload
* _handle_http_error is not called
"""
self.sender._auth_token = "my-auth-token"
sender_create_request_url.return_value = \
"http://my-endpoint/v1/metric/my-metrid-id/measures"
expected_args = (
"http://my-endpoint/v1/metric/my-metrid-id/measures",
"some-payload",
"my-auth-token")
self.sender.send("my-metername", "some-payload", unit="some-unit")
sender_perform_request.assert_called_with(*expected_args)
@mock.patch.object(gnocchi_sender.Sender, '_handle_http_error')
@mock.patch('requests.post')
@mock.patch.object(gnocchi_sender.Sender, '_create_request_url')
@mock.patch.object(gnocchi_sender.Sender, '_authenticate')
def test_send_error_404(self, sender_authenticate,
sender_create_request_url,
post,
sender_handle_http_err):
"""Test send when metric is not defined
Tests what happens when metric is not defined i.e. 404 is returned
Set-up:
Test: post returns a 404 when attenpting to create a measure
Expected behaviour:
* _handle_http_request is called to handle the 404
"""
response_not_found = requests.Response()
response_not_found.status_code = 404
exc = requests.exceptions.HTTPError(
u'404 Client Error: None for url: None',
response=response_not_found)
# send() mock the steps moving up to _perform_request
sender_authenticate.return_value = "my_auth_token"
sender_create_request_url.return_value = "http://my-request-url"
# When the request is made, it fails
post.return_value = exc.response
self.sender.send("my-meter", "payload", resource_id="my-resource")
sender_handle_http_err.assert_called()
@mock.patch.object(gnocchi_sender.Sender, '_get_endpoint')
def test_on_authenticated(self, sender_get_endpoint):
"""Test sender._on_authenticated
Set-up: None
Test: Call sender._on_authenticated
Expected behaviour: sender._url_base is set correctly
"""
expected_url = \
"http://my-endpoint/v1/metric/%s/measures"
sender_get_endpoint.return_value = "http://my-endpoint"
self.sender._on_authenticated()
self.assertEqual(self.sender._url_base,
expected_url)
@mock.patch.object(gnocchi_sender.Sender, '_get_metric_id')
@mock.patch.object(gnocchi_sender.Sender, '_get_endpoint')
def test_create_request_url(self, sender_get_endpoint,
sender_get_metric_id):
"""Test create_request_url
Set-up: None
Test: call _create_requet_url
Expected behaviour: sender_url_base is is returned
"""
expected_url = \
"http://my-endpoint/v1/metric/my-metric-name/measures"
sender_get_endpoint.return_value = "http://my-endpoint"
sender_get_metric_id.return_value = "my-metric-name"
url = self.sender._create_request_url("my-metric-name", unit="my-unit")
self.assertEqual(url,
expected_url)
def test_handle_http_error(self):
"""Tesing the response to a HTTPError that is not a 404.
Set-up: Create an Exception to use as a parameter
Test: Use exception as an input parameter
Expected behaviour: exception is raised again
"""
res = requests.Response()
res.status_code = 402
exc = requests.HTTPError("Oh no! there was an error!",
response=res)
self.assertRaises(requests.exceptions.HTTPError,
self.sender._handle_http_error,
exc, "my-meter", "some-payload", "my-auth-token")
@mock.patch.object(gnocchi_sender.Sender, '_get_metric_id')
@mock.patch.object(gnocchi_sender.Sender, '_perform_request', autospec=True)
def test_handle_http_error_404(self, sender_perf_req,
sender_get_metric_id):
"""Test response to a HTTP 404 Error
Set-up: Create the HTTPError
Test: Call _handle_http_error with appropriate inputs
Expected behaviour:
* Sender will try to create_or_update_resource
"""
res = requests.Response()
res.status_code = 404
exc = requests.exceptions.HTTPError("Oh no! It wasn't found!",
response=res)
success = requests.Response()
success.status_code = 201
sender_perf_req.return_value = success
sender_get_metric_id.return_value = "my-metric-name"
self.sender._handle_http_error(exc, "my-meter", "some-payload",
"my-auth-token", unit="my-unit",
resource_id="my-resource-id")

View File

@ -16,10 +16,13 @@
# under the License.
"""Gnocchi Writer tests"""
import json
import mock
import requests
import unittest
from collectd_openstack.common.meters import MeterStorage
from collectd_openstack.gnocchi import sender as gnocchi_sender
from collectd_openstack.gnocchi import writer
@ -110,3 +113,112 @@ class TestGnocchiWriter(unittest.TestCase):
meters = MeterStorage(collectd=collectd)
self.writer = writer.Writer(meters=meters, config=config)
self.writer._sender._auth_token = "my_auth_token"
@mock.patch.object(gnocchi_sender.Sender, '_create_request_url')
@mock.patch.object(gnocchi_sender.Sender, '_get_endpoint')
@mock.patch.object(gnocchi_sender.Sender, '_authenticate')
@mock.patch('requests.post', autospec=True)
@mock_value()
def test_write(self, vl, post, sender_authenticate, sender_get_endpoint,
sender_create_request_url):
"""Test write with successful results
Set-up: None
Test: call write with expected data
Expected behaviour:
* POST is called successfully
* No error occurs i.e. no error is raised
"""
response_ok = requests.Response()
response_ok.status_code = 200
post.return_value = response_ok
self.writer._sender._url_base = "my-url"
sender_get_endpoint.return_value = "http://my-endpoint"
sender_create_request_url.return_value = \
"http://my-endpoint/v1/metrics/my-metric-id/measures"
sender_authenticate.return_value = "auth_token"
# Force the url to be updated without actually authenticating
self.writer._sender._on_authenticated()
expected_url = "http://my-endpoint/v1/metrics/my-metric-id/measures"
expected_payload = json.dumps([
{
"value": 1234,
"timestamp": "1973-11-29T21:33:09"
},
])
expected_kwargs = {"data": expected_payload,
"headers": mock.ANY,
"timeout": mock.ANY}
self.writer.write(vl, None)
post.assert_called_with(expected_url, **expected_kwargs)
@mock.patch.object(gnocchi_sender.Sender, '_get_endpoint')
@mock.patch.object(gnocchi_sender.Sender, '_authenticate')
@mock.patch.object(gnocchi_sender.Sender, '_create_metric')
@mock.patch('requests.post', autospec=True)
@mock_value()
def test_write_metric_none(self, vl, post,
sender_create_metric,
sender_authenticate,
sender_get_endpoint):
"""Test Writer.write() when there is no meter defined.
Set-up:
Test: Sender throws a HTTPError with status=404
Expected behaviour:
* _create_or_update_resource is called with appropriate args
"""
response_not_found = requests.Response()
response_not_found.status_code = 404
response_ok = requests.Response()
response_ok.status_code = 200
# post will be called to submit sample before AND after handling
# the error
post.side_effect = [response_not_found, response_ok]
self.writer._sender._url_base = "my-url"
sender_get_endpoint.return_value = "http://my-endpoint"
sender_authenticate.return_value = "auth_token"
self.writer.write(vl, data=None)
sender_create_metric.assert_called()
@mock.patch.object(gnocchi_sender.Sender, 'send')
@mock_value()
def test_send_data(self, vl, sender_send):
"""Test _send_data() to make sure the correct payoad is being sent.
Set-up: Create a sample
Test: call _send_data
Expected behaviour:
* Sender.send() is called with the correct payload and args
"""
sample = writer.Sample(value=42, timestamp=0, meta=None,
unit="my-unit", metername="my-metername")
# TODO(emma-l-foley): Add docstring to _send_data specifying the inputs.
# to_send should be a list of Sample objects
to_send = [sample]
expected_payload = json.dumps([
{
"value": 42,
"timestamp": 0
}
])
expected_args = ("my-metername", expected_payload)
expected_kwargs = {"unit": "my-unit"}
self.writer._send_data("my-metername", to_send,
unit="my-unit",)
sender_send.assert_called_with(*expected_args, **expected_kwargs)