349 lines
15 KiB
Python
Executable File
349 lines
15 KiB
Python
Executable File
# Copyright 2013 IBM Corp
|
|
#
|
|
# 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.
|
|
|
|
import falcon
|
|
import mock
|
|
from oslo_config import fixture as fixture_config
|
|
from oslotest import base
|
|
import requests
|
|
|
|
from kiloeyes.common import kafka_conn
|
|
from kiloeyes.v2.elasticsearch import metrics
|
|
|
|
try:
|
|
import ujson as json
|
|
except ImportError:
|
|
import json
|
|
|
|
|
|
class TestParamUtil(base.BaseTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestParamUtil, self).setUp()
|
|
self.req = mock.Mock()
|
|
self.req.get_param.side_effect = self._side_effect
|
|
|
|
def _side_effect(self, arg):
|
|
if arg == 'name':
|
|
return 'tongli'
|
|
elif arg == 'dimensions':
|
|
return 'key1:100, key2:200'
|
|
elif arg == 'start_time':
|
|
return '2015-01-31T13:35:00Z'
|
|
elif arg == 'end_time':
|
|
return '2015-11-30T14:05:00Z'
|
|
elif arg == 'period':
|
|
return '200'
|
|
elif arg == 'statistics':
|
|
return 'sum, avg'
|
|
|
|
def test_common(self):
|
|
result = [{'match': {'name': 'tongli'}},
|
|
{'range': {'timestamp': {'gte': 1422711300.0,
|
|
'lt': 1448892300.0}}},
|
|
{'match': {'dimensions.key1': 100.0}},
|
|
{'match': {'dimensions.key2': 200.0}}]
|
|
|
|
q = []
|
|
ret = metrics.ParamUtil.common(self.req, q)
|
|
self.assertEqual(q, result)
|
|
self.assertTrue(ret)
|
|
|
|
def test_period(self):
|
|
ret = metrics.ParamUtil.period(self.req)
|
|
self.assertEqual(ret, '200s')
|
|
|
|
def test_stats(self):
|
|
ret = metrics.ParamUtil.stats(self.req)
|
|
self.assertEqual(ret, ['sum', 'avg'])
|
|
|
|
|
|
class TestMetricDispatcher(base.BaseTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestMetricDispatcher, self).setUp()
|
|
self.CONF = self.useFixture(fixture_config.Config()).conf
|
|
self.CONF.set_override('uri', 'fake_url', group='kafka_opts')
|
|
self.CONF.set_override('topic', 'fake', group='metrics')
|
|
self.CONF.set_override('doc_type', 'fake', group='metrics')
|
|
self.CONF.set_override('index_prefix', 'also_fake', group='metrics')
|
|
self.CONF.set_override('index_template', 'etc/metrics.template',
|
|
group='metrics')
|
|
self.CONF.set_override('uri', 'http://fake_es_uri', group='es_conn')
|
|
|
|
res = mock.Mock()
|
|
res.status_code = 200
|
|
res.json.return_value = {"data": {"mappings": {"fake": {
|
|
"properties": {
|
|
"dimensions": {"properties": {
|
|
"key1": {"type": "long"}, "key2": {"type": "long"},
|
|
"rkey0": {"type": "long"}, "rkey1": {"type": "long"},
|
|
"rkey2": {"type": "long"}, "rkey3": {"type": "long"}}},
|
|
"name": {"type": "string", "index": "not_analyzed"},
|
|
"timestamp": {"type": "string", "index": "not_analyzed"},
|
|
"value": {"type": "double"}}}}}}
|
|
put_res = mock.Mock()
|
|
put_res.status_code = '200'
|
|
with mock.patch.object(requests, 'get',
|
|
return_value=res):
|
|
with mock.patch.object(requests, 'put', return_value=put_res):
|
|
self.dispatcher = metrics.MetricDispatcher({})
|
|
|
|
def test_initialization(self):
|
|
# test that the kafka connection uri should be 'fake' as it was passed
|
|
# in from configuration
|
|
self.assertEqual(self.dispatcher._kafka_conn.uri, 'fake_url')
|
|
|
|
# test that the topic is metrics as it was passed into dispatcher
|
|
self.assertEqual(self.dispatcher._kafka_conn.topic, 'fake')
|
|
|
|
# test that the doc type of the es connection is fake
|
|
self.assertEqual(self.dispatcher._es_conn.doc_type, 'fake')
|
|
|
|
self.assertEqual(self.dispatcher._es_conn.uri, 'http://fake_es_uri/')
|
|
|
|
# test that the query url is correctly formed
|
|
self.assertEqual(self.dispatcher._query_url, (
|
|
'http://fake_es_uri/also_fake*/fake/_search?search_type=count'))
|
|
|
|
def test_post_data(self):
|
|
with mock.patch.object(kafka_conn.KafkaConnection, 'send_messages',
|
|
return_value=204):
|
|
res = mock.Mock()
|
|
self.dispatcher.post_data(mock.Mock(), res)
|
|
|
|
# test that the response code is 204
|
|
self.assertEqual(getattr(falcon, 'HTTP_204'), res.status)
|
|
|
|
with mock.patch.object(kafka_conn.KafkaConnection, 'send_messages',
|
|
return_value=400):
|
|
res = mock.Mock()
|
|
self.dispatcher.post_data(mock.Mock(), res)
|
|
|
|
# test that the response code is 204
|
|
self.assertEqual(getattr(falcon, 'HTTP_400'), res.status)
|
|
|
|
def test_do_get_metrics(self):
|
|
res = mock.Mock()
|
|
req = mock.Mock()
|
|
|
|
def _side_effect(arg):
|
|
if arg == 'name':
|
|
return 'tongli'
|
|
elif arg == 'dimensions':
|
|
return 'key1:100, key2:200'
|
|
req.get_param.side_effect = _side_effect
|
|
|
|
req_result = mock.Mock()
|
|
response_str = """
|
|
{"aggregations":{"by_name":{"doc_count_error_upper_bound":0,
|
|
"sum_other_doc_count":0,"buckets":[{"key":"BABMGD","doc_count":300,
|
|
"by_dim":{"buckets":[{"key": "64e6ce08b3b8547b7c32e5cfa5b7d81f",
|
|
"doc_count":300,"metrics":{"hits":{"hits":[{
|
|
"_source":{"name":"BABMGD","dimensions":{"key2":"NVITDU",
|
|
"key1":"FUFMPY","key_43":"ROQBZM"}}}]}}}]}},
|
|
{"key":"BABSYZ","doc_count":300,"by_dim":{"buckets":[{
|
|
"key":"84863c7cfee6837a77eb476ea9f35f87","doc_count":300,
|
|
"metrics":{"hits":{"hits":[{"_source":{"name":"BABSYZ",
|
|
"dimensions":{"key2":"UIPAJD","key1":"DKPNKA",
|
|
"key_10": "RADAJP"}}}]}}}]}}]}}}
|
|
"""
|
|
|
|
req_result.json.return_value = json.loads(response_str)
|
|
req_result.status_code = 200
|
|
|
|
with mock.patch.object(requests, 'post', return_value=req_result):
|
|
self.dispatcher.do_get_metrics(req, res)
|
|
|
|
# test that the response code is 200
|
|
self.assertEqual(res.status, getattr(falcon, 'HTTP_200'))
|
|
obj = json.loads(res.body)
|
|
self.assertEqual(obj[0]['name'], 'BABMGD')
|
|
self.assertEqual(obj[0]['dimensions']['key2'], 'NVITDU')
|
|
self.assertEqual(len(obj), 2)
|
|
|
|
def test_do_post_metrics(self):
|
|
with mock.patch.object(kafka_conn.KafkaConnection, 'send_messages',
|
|
return_value=204):
|
|
res = mock.Mock()
|
|
self.dispatcher.do_post_metrics(mock.Mock(), res)
|
|
|
|
self.assertEqual(getattr(falcon, 'HTTP_204'), res.status)
|
|
|
|
def test_do_get_measurements(self):
|
|
res = mock.Mock()
|
|
req = mock.Mock()
|
|
|
|
def _side_effect(arg):
|
|
if arg == 'name':
|
|
return 'tongli'
|
|
elif arg == 'dimensions':
|
|
return 'key1:100, key2:200'
|
|
elif arg == 'start_time':
|
|
return '2014-01-01'
|
|
|
|
req.get_param.side_effect = _side_effect
|
|
|
|
req_result = mock.Mock()
|
|
response_str = """
|
|
{"took":226,"timed_out":false,"_shards":{"total":5,"successful":5,
|
|
"failed":0},"hits":{"total":6600,"max_score":0.0,"hits":[]},
|
|
"aggregations":{"by_name":{"doc_count_error_upper_bound":293,
|
|
"sum_other_doc_count":5791,"buckets":[{"key":"ABYTPK",
|
|
"doc_count":300,"by_dim":{"doc_count_error_upper_bound":0,
|
|
"sum_other_doc_count":0,
|
|
"buckets":[{"key":"e62ef04ee44abcccdd177087d159c1e3","doc_count":300,
|
|
"dimension":{"hits":{"total":300,"max_score":1.4142135,
|
|
"hits":[{"_index":"data_20150121","_type":"metrics",
|
|
"_id":"AUsShaLKTZaMxA7_0_Hj","_score":1.4142135,
|
|
"_source":{"name":"ABYTPK","dimensions":{"key_81":"MKKNSA",
|
|
"key2":"TJJQGE","key1":"GYYLEG"}}}]}},
|
|
"measures":{"hits":{"total":300,"max_score":null,
|
|
"hits":[{"_index":"data_20150121","_type":"metrics",
|
|
"_id":"AUsShaKuTZaMxA7_0_Hd","_score":null,
|
|
"_source":{"timestamp":1.421944922765286E9,"value":0.0},
|
|
"sort":[1.421944922765286E9]},{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsShaM8TZaMxA7_0_H7",
|
|
"_score":null,"_source":{"timestamp":1.421944922907783E9,
|
|
"value":0.0},"sort":[1.421944922907783E9]},{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsShaR2TZaMxA7_0_IZ","_score":null,
|
|
"_source":{"timestamp":1.421944923222439E9,"value":0.0},
|
|
"sort":[1.421944923222439E9]}]}}}]}},{"key":"ABUYPI","doc_count":256,
|
|
"by_dim":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,
|
|
"buckets":[{"key":"3dba425d350f6f46f8eda8a883231e58",
|
|
"doc_count":256,"dimension":{"hits":{"total":256,
|
|
"max_score":1.4142135,"hits":[{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsSaTfYTZaMxA7_zaxn","_score":1.4142135,
|
|
"_source":{"name":"ABUYPI","dimensions":{"key2":"BEBGIY",
|
|
"key1":"JZAZQS","key_67":"EAJWVV"}}}]}},
|
|
"measures":{"hits":{"total":256,"max_score":null,
|
|
"hits":[{"_index":"data_20150121","_type":"metrics",
|
|
"_id":"AUsSaTfQTZaMxA7_zaxl","_score":null,
|
|
"_source":{"timestamp":1.421943060399819E9,"value":0.0},
|
|
"sort":[1.421943060399819E9]},{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsSaThJTZaMxA7_zayD","_score":null,
|
|
"_source":{"timestamp":1.421943060519964E9,"value":0.0},
|
|
"sort":[1.421943060519964E9]},{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsSaTjKTZaMxA7_zayh","_score":null,
|
|
"_source":{"timestamp":1.421943060648909E9,"value":0.0},
|
|
"sort":[1.421943060648909E9]}]}}}]}},
|
|
{"key":"ABEPJR","doc_count":253,
|
|
"by_dim":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,
|
|
"buckets":[{"key":"6d6bbdda3ed7f14c76e746e2fbd52a37",
|
|
"doc_count":253,"dimension":{"hits":{"total":253,
|
|
"max_score":1.4142135,"hits":[{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsR6STQTZaMxA7_sjp6",
|
|
"_score":1.4142135,"_source":{"name":"ABEPJR",
|
|
"dimensions":{"key_7":"ZAUVQN","key2":"NSXBUW","key1":"UXTDSW"}}}]}},
|
|
"measures":{"hits":{"total":253,"max_score":null,
|
|
"hits":[{"_index":"data_20150121","_type":"metrics",
|
|
"_id":"AUsR6SItTZaMxA7_sjnV","_score":null,
|
|
"_source":{"timestamp":1.421934666252589E9,"value":0.0},
|
|
"sort":[1.421934666252589E9]},{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsR6SKqTZaMxA7_sjnz","_score":null,
|
|
"_source":{"timestamp":1.421934666377047E9,"value":0.0},
|
|
"sort":[1.421934666377047E9]},{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsR6SMiTZaMxA7_sjoR","_score":null,
|
|
"_source":{"timestamp":1.421934666497888E9,"value":0.0},
|
|
"sort":[1.421934666497888E9]}]}}}]}}]}}}
|
|
"""
|
|
req_result.json.return_value = json.loads(response_str)
|
|
|
|
req_result.status_code = 200
|
|
|
|
with mock.patch.object(requests, 'post', return_value=req_result):
|
|
self.dispatcher.do_get_measurements(req, res)
|
|
|
|
# test that the response code is 200
|
|
self.assertEqual(res.status, getattr(falcon, 'HTTP_200'))
|
|
obj = json.loads(res.body)
|
|
|
|
# there should be total of 3 objects
|
|
self.assertEqual(len(obj), 3)
|
|
self.assertIsNotNone(obj[0]['name'])
|
|
self.assertIsNotNone(obj[0]['dimensions'])
|
|
self.assertIsNotNone(obj[0]['columns'])
|
|
self.assertIsNotNone(obj[0]['measurements'])
|
|
|
|
def test_do_get_statistics(self):
|
|
res = mock.Mock()
|
|
req = mock.Mock()
|
|
|
|
def _side_effect(arg):
|
|
if arg == 'name':
|
|
return 'tongli'
|
|
elif arg == 'dimensions':
|
|
return 'key1:100, key2:200'
|
|
elif arg == 'start_time':
|
|
return '2014-01-01'
|
|
elif arg == 'end_time':
|
|
return None
|
|
elif arg == 'period':
|
|
return None
|
|
elif arg == 'statistics':
|
|
return 'avg, sum, max'
|
|
|
|
req.get_param.side_effect = _side_effect
|
|
|
|
req_result = mock.Mock()
|
|
response_str = """
|
|
{"took":2006,"timed_out":false,"_shards":{"total":5,"successful":5,
|
|
"failed":0},"hits":{"total":600,"max_score":0.0,"hits":[]},
|
|
"aggregations":{"by_name":{"doc_count_error_upper_bound":0,
|
|
"sum_other_doc_count":0,"buckets":[{"key":"BABMGD","doc_count":300,
|
|
"by_dim":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,
|
|
"buckets":[{"key":"64e6ce08b3b8547b7c32e5cfa5b7d81f","doc_count":300,
|
|
"periods":{"buckets":[{"key":1421700000,"doc_count":130,
|
|
"statistics":{"count":130,"min":0.0,"max":595.0274095324651,
|
|
"avg":91.83085293930924,"sum":11938.0108821102}},
|
|
{"key":1422000000,"doc_count":170,"statistics":{"count":170,
|
|
"min":0.0,"max":1623.511307756313,"avg":324.69434786459897,
|
|
"sum":55198.039136981824}}]},"dimension":{"hits":{"total":300,
|
|
"max_score":1.4142135,"hits":[{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsSNF5mTZaMxA7_wmFx","_score":1.4142135,
|
|
"_source":{"name":"BABMGD","dimensions":{"key2":"NVITDU",
|
|
"key1":"FUFMPY","key_43":"ROQBZM"}}}]}}}]}},{"key":"BABSYZ",
|
|
"doc_count":300,"by_dim":{"doc_count_error_upper_bound":0,
|
|
"sum_other_doc_count":0,
|
|
"buckets":[{"key":"84863c7cfee6837a77eb476ea9f35f87","doc_count":300,
|
|
"periods":{"buckets":[{"key":1421700000,"doc_count":130,
|
|
"statistics":{"count":130,"min":0.0,"max":588.7273873368565,
|
|
"avg":100.45023098906705,"sum":13058.530028578716}},
|
|
{"key":1422000000,"doc_count":170,"statistics":{"count":170,
|
|
"min":0.0,"max":1515.5538517109185,"avg":332.5777043693029,
|
|
"sum":56538.209742781495}}]},"dimension":{"hits":{"total":300,
|
|
"max_score":1.4142135,"hits":[{"_index":"data_20150121",
|
|
"_type":"metrics","_id":"AUsR7oGETZaMxA7_s0Y0","_score":1.4142135,
|
|
"_source":{"name":"BABSYZ","dimensions":{"key2":"UIPAJD",
|
|
"key1":"DKPNKA","key_10":"RADAJP"}}}]}}}]}}]}}}
|
|
"""
|
|
req_result.json.return_value = json.loads(response_str)
|
|
|
|
req_result.status_code = 200
|
|
|
|
with mock.patch.object(requests, 'post', return_value=req_result):
|
|
self.dispatcher.do_get_statistics(req, res)
|
|
|
|
# test that the response code is 200
|
|
self.assertEqual(res.status, getattr(falcon, 'HTTP_200'))
|
|
obj = json.loads(res.body)
|
|
# there should be total of 2 objects
|
|
self.assertEqual(len(obj), 2)
|
|
self.assertIsNotNone(obj[0]['name'])
|
|
self.assertIsNotNone(obj[0]['dimensions'])
|
|
self.assertIsNotNone(obj[0]['columns'])
|
|
self.assertEqual(obj[0]['columns'],
|
|
["timestamp", "avg", "sum", "max"])
|
|
self.assertIsNotNone(obj[0]['statistics'])
|