"Fossies" - the Fresh Open Source Software Archive

Member "cloudkitty-9.0.0/cloudkitty/tests/collectors/test_prometheus.py" (10 Apr 2019, 10872 Bytes) of package /linux/misc/openstack/cloudkitty-9.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_prometheus.py": 8.0.0_vs_9.0.0.

    1 # -*- coding: utf-8 -*-
    2 # Copyright 2018 Objectif Libre
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 #
   16 # @author: Martin CAMEY
   17 #
   18 from decimal import Decimal
   19 
   20 import mock
   21 
   22 from cloudkitty import collector
   23 from cloudkitty.collector import prometheus
   24 from cloudkitty import json_utils as json
   25 from cloudkitty import tests
   26 from cloudkitty.tests import samples
   27 from cloudkitty import transformer
   28 
   29 
   30 class PrometheusCollectorTest(tests.TestCase):
   31     def setUp(self):
   32         super(PrometheusCollectorTest, self).setUp()
   33         self._tenant_id = samples.TENANT
   34         args = {
   35             'period': 3600,
   36             'scope_key': 'namespace',
   37             'conf': {
   38                 'metrics': {
   39                     'http_requests_total': {
   40                         'unit': 'instance',
   41                         'groupby': [
   42                             'foo',
   43                             'bar',
   44                         ],
   45                         'metadata': [
   46                             'code',
   47                             'instance',
   48                         ],
   49                         'extra_args': {
   50                             'aggregation_method': 'avg',
   51                         },
   52                     },
   53                 }
   54             }
   55         }
   56         transformers = transformer.get_transformers()
   57         self.collector = prometheus.PrometheusCollector(transformers, **args)
   58 
   59     def test_fetch_all_build_query(self):
   60         query = (
   61             'avg(avg_over_time(http_requests_total'
   62             '{project_id="f266f30b11f246b589fd266f85eeec39"}[3600s]'
   63             ')) by (foo, bar, project_id, code, instance)'
   64         )
   65 
   66         with mock.patch.object(
   67             prometheus.PrometheusClient, 'get_instant',
   68         ) as mock_get:
   69             self.collector.fetch_all(
   70                 'http_requests_total',
   71                 samples.FIRST_PERIOD_BEGIN,
   72                 samples.FIRST_PERIOD_END,
   73                 self._tenant_id,
   74             )
   75             mock_get.assert_called_once_with(
   76                 query,
   77                 samples.FIRST_PERIOD_END,
   78             )
   79 
   80     def test_format_data_instant_query(self):
   81         expected = ({
   82             'code': '200',
   83             'instance': 'localhost:9090',
   84         }, {
   85             'bar': '',
   86             'foo': '',
   87             'project_id': ''
   88         }, Decimal('7'))
   89 
   90         params = {
   91             'metric_name': 'http_requests_total',
   92             'scope_key': 'project_id',
   93             'scope_id': self._tenant_id,
   94             'start': samples.FIRST_PERIOD_BEGIN,
   95             'end': samples.FIRST_PERIOD_END,
   96             'data': samples.PROMETHEUS_RESP_INSTANT_QUERY['data']['result'][0],
   97         }
   98         actual = self.collector._format_data(**params)
   99         self.assertEqual(expected, actual)
  100 
  101     def test_format_data_instant_query_2(self):
  102         expected = ({
  103             'code': '200',
  104             'instance': 'localhost:9090',
  105         }, {
  106             'bar': '',
  107             'foo': '',
  108             'project_id': ''
  109         }, Decimal('42'))
  110 
  111         params = {
  112             'metric_name': 'http_requests_total',
  113             'scope_key': 'project_id',
  114             'scope_id': self._tenant_id,
  115             'start': samples.FIRST_PERIOD_BEGIN,
  116             'end': samples.FIRST_PERIOD_END,
  117             'data': samples.PROMETHEUS_RESP_INSTANT_QUERY['data']['result'][1],
  118         }
  119         actual = self.collector._format_data(**params)
  120         self.assertEqual(expected, actual)
  121 
  122     def test_format_retrieve(self):
  123         expected = {
  124             'http_requests_total': [
  125                 {
  126                     'desc': {
  127                         'bar': '', 'foo': '', 'project_id': '',
  128                         'code': '200', 'instance': 'localhost:9090',
  129                     },
  130                     'groupby': {'bar': '', 'foo': '', 'project_id': ''},
  131                     'metadata': {'code': '200', 'instance': 'localhost:9090'},
  132                     'vol': {
  133                         'qty': Decimal('7'),
  134                         'unit': 'instance'
  135                     }
  136                 },
  137                 {
  138                     'desc': {
  139                         'bar': '', 'foo': '', 'project_id': '',
  140                         'code': '200', 'instance': 'localhost:9090',
  141                     },
  142                     'groupby': {'bar': '', 'foo': '', 'project_id': ''},
  143                     'metadata': {'code': '200', 'instance': 'localhost:9090'},
  144                     'vol': {
  145                         'qty': Decimal('42'),
  146                         'unit': 'instance'
  147                     }
  148                 }
  149             ]
  150         }
  151 
  152         no_response = mock.patch(
  153             'cloudkitty.collector.prometheus.PrometheusClient.get_instant',
  154             return_value=samples.PROMETHEUS_RESP_INSTANT_QUERY,
  155         )
  156 
  157         with no_response:
  158             actual = self.collector.retrieve(
  159                 metric_name='http_requests_total',
  160                 start=samples.FIRST_PERIOD_BEGIN,
  161                 end=samples.FIRST_PERIOD_END,
  162                 project_id=samples.TENANT,
  163                 q_filter=None,
  164             )
  165 
  166         self.assertEqual(expected, actual)
  167 
  168     def test_format_retrieve_raise_NoDataCollected(self):
  169         no_response = mock.patch(
  170             'cloudkitty.collector.prometheus.PrometheusClient.get_instant',
  171             return_value=samples.PROMETHEUS_EMPTY_RESP_INSTANT_QUERY,
  172         )
  173 
  174         with no_response:
  175             self.assertRaises(
  176                 collector.NoDataCollected,
  177                 self.collector.retrieve,
  178                 metric_name='http_requests_total',
  179                 start=samples.FIRST_PERIOD_BEGIN,
  180                 end=samples.FIRST_PERIOD_END,
  181                 project_id=samples.TENANT,
  182                 q_filter=None,
  183             )
  184 
  185 
  186 class PrometheusClientTest(tests.TestCase):
  187 
  188     class FakeResponse(object):
  189         """Mimics an HTTP ``requests`` response"""
  190 
  191         def __init__(self, url, text, status_code):
  192             self.url = url
  193             self.text = text
  194             self.status_code = status_code
  195 
  196         def json(self):
  197             return json.loads(self.text)
  198 
  199     @staticmethod
  200     def _mock_requests_get(text):
  201         """Factory to build FakeResponse with desired response body text"""
  202         return lambda *args, **kwargs: PrometheusClientTest.FakeResponse(
  203             args[0], text, 200,
  204         )
  205 
  206     def setUp(self):
  207         super(PrometheusClientTest, self).setUp()
  208         self.client = prometheus.PrometheusClient(
  209             'http://localhost:9090/api/v1',
  210         )
  211 
  212     def test_get_with_no_options(self):
  213         with mock.patch('requests.get') as mock_get:
  214             self.client._get(
  215                 'query_range',
  216                 params={
  217                     'query': 'max(http_requests_total) by (project_id)',
  218                     'start': samples.FIRST_PERIOD_BEGIN,
  219                     'end': samples.FIRST_PERIOD_END,
  220                     'step': 10,
  221                 },
  222             )
  223             mock_get.assert_called_once_with(
  224                 'http://localhost:9090/api/v1/query_range',
  225                 params={
  226                     'query': 'max(http_requests_total) by (project_id)',
  227                     'start': samples.FIRST_PERIOD_BEGIN,
  228                     'end': samples.FIRST_PERIOD_END,
  229                     'step': 10,
  230                 },
  231                 auth=None,
  232                 verify=True,
  233             )
  234 
  235     def test_get_with_options(self):
  236         client = prometheus.PrometheusClient(
  237             'http://localhost:9090/api/v1',
  238             auth=('foo', 'bar'),
  239             verify='/some/random/path',
  240         )
  241         with mock.patch('requests.get') as mock_get:
  242             client._get(
  243                 'query_range',
  244                 params={
  245                     'query': 'max(http_requests_total) by (project_id)',
  246                     'start': samples.FIRST_PERIOD_BEGIN,
  247                     'end': samples.FIRST_PERIOD_END,
  248                     'step': 10,
  249                 },
  250             )
  251             mock_get.assert_called_once_with(
  252                 'http://localhost:9090/api/v1/query_range',
  253                 params={
  254                     'query': 'max(http_requests_total) by (project_id)',
  255                     'start': samples.FIRST_PERIOD_BEGIN,
  256                     'end': samples.FIRST_PERIOD_END,
  257                     'step': 10,
  258                 },
  259                 auth=('foo', 'bar'),
  260                 verify='/some/random/path',
  261             )
  262 
  263     def test_get_instant(self):
  264         mock_get = mock.patch(
  265             'requests.get',
  266             side_effect=self._mock_requests_get('{"foo": "bar"}'),
  267         )
  268 
  269         with mock_get:
  270             res = self.client.get_instant(
  271                 'max(http_requests_total) by (project_id)',
  272             )
  273             self.assertEqual(res, {'foo': 'bar'})
  274 
  275     def test_get_range(self):
  276         mock_get = mock.patch(
  277             'requests.get',
  278             side_effect=self._mock_requests_get('{"foo": "bar"}'),
  279         )
  280 
  281         with mock_get:
  282             res = self.client.get_range(
  283                 'max(http_requests_total) by (project_id)',
  284                 samples.FIRST_PERIOD_BEGIN,
  285                 samples.FIRST_PERIOD_END,
  286                 10,
  287             )
  288             self.assertEqual(res, {'foo': 'bar'})
  289 
  290     def test_get_instant_raises_error_on_bad_json(self):
  291         # Simulating malformed JSON response from HTTP+PromQL instant request
  292         mock_get = mock.patch(
  293             'requests.get',
  294             side_effect=self._mock_requests_get('{"foo": "bar"'),
  295         )
  296         with mock_get:
  297             self.assertRaises(
  298                 prometheus.PrometheusResponseError,
  299                 self.client.get_instant,
  300                 'max(http_requests_total) by (project_id)',
  301             )
  302 
  303     def test_get_range_raises_error_on_bad_json(self):
  304         # Simulating malformed JSON response from HTTP+PromQL range request
  305         mock_get = mock.patch(
  306             'requests.get',
  307             side_effect=self._mock_requests_get('{"foo": "bar"'),
  308         )
  309         with mock_get:
  310             self.assertRaises(
  311                 prometheus.PrometheusResponseError,
  312                 self.client.get_range,
  313                 'max(http_requests_total) by (project_id)',
  314                 samples.FIRST_PERIOD_BEGIN,
  315                 samples.FIRST_PERIOD_END,
  316                 10,
  317             )