From 9f5b776c1b5a54d2ca5942424111f3ff55d5737c Mon Sep 17 00:00:00 2001 From: Mark Beierl Date: Fri, 2 Dec 2016 22:25:48 -0500 Subject: Steady state detection Detection of steady state after 10+ samples of data Change-Id: I29368b06188c6370d17b3d567fece6486d171235 JIRA: STORPERF-72 STORPERF-73 Signed-off-by: Mark Beierl --- tests/carbon_tests/emitter_test.py | 18 ++- tests/db_tests/graphite_db_test.py | 59 +++++++++- tests/utilities_tests/data_handler_test.py | 170 +++++++++++++++++++++++++++-- tests/utilities_tests/math_slope_test.py | 5 + 4 files changed, 238 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/carbon_tests/emitter_test.py b/tests/carbon_tests/emitter_test.py index fe19ed2..7f61049 100644 --- a/tests/carbon_tests/emitter_test.py +++ b/tests/carbon_tests/emitter_test.py @@ -7,14 +7,16 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from storperf.carbon import converter -from storperf.carbon.emitter import CarbonMetricTransmitter -from time import sleep import SocketServer import json +from storperf.carbon import converter +from storperf.carbon.emitter import CarbonMetricTransmitter import threading +from time import sleep, strptime import unittest +import mock + class MetricsHandler(SocketServer.BaseRequestHandler): @@ -42,10 +44,14 @@ class CarbonMetricTransmitterTest(unittest.TestCase): t.setDaemon(True) t.start() - def test_transmit_metrics(self): + @mock.patch("time.gmtime") + def test_transmit_metrics(self, mock_time): + + mock_time.return_value = strptime("30 Nov 00", "%d %b %y") testconv = converter.Converter() - json_object = json.loads("""{"timestamp" : "12345", "key":"value" }""") + json_object = json.loads( + """{"timestamp" : "975542400", "key":"value" }""") result = testconv.convert_json_to_flat(json_object, "host.run-name") emitter = CarbonMetricTransmitter() @@ -58,7 +64,7 @@ class CarbonMetricTransmitterTest(unittest.TestCase): count += 1 sleep(0.1) - self.assertEqual("host.run-name.key value 12345\n", + self.assertEqual("host.run-name.key value 975542400\n", CarbonMetricTransmitterTest.response, CarbonMetricTransmitterTest.response) diff --git a/tests/db_tests/graphite_db_test.py b/tests/db_tests/graphite_db_test.py index e13545b..d4c6fb6 100644 --- a/tests/db_tests/graphite_db_test.py +++ b/tests/db_tests/graphite_db_test.py @@ -7,9 +7,19 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from storperf.db.graphite_db import GraphiteDB import unittest +import mock + +from storperf.db.graphite_db import GraphiteDB + + +class MockResponse(): + + def __init__(self): + self.content = "" + self.status_code = 200 + class GraphiteDBTest(unittest.TestCase): @@ -32,6 +42,53 @@ class GraphiteDBTest(unittest.TestCase): # self.graphdb.fetch_averages(u'32d31724-fac1-44f3-9033-ca8e00066a36') pass + @mock.patch("requests.get") + def test_fetch_series(self, mock_requests): + + response = MockResponse() + response.content = """ +[ + { + "datapoints": [ + [null,1480455880], + [null,1480455890], + [null,1480455900], + [205.345,1480455910], + [201.59,1480455920], + [205.76,1480455930], + [null,1480455940], + [null,1480455950], + [null,1480455960], + [215.655,1480455970], + [214.16,1480455980], + [213.57,1480455990], + [null,1480456000], + [null,1480456010], + [null,1480456020], + [219.37,1480456030], + [219.28,1480456040], + [217.75,1480456050], + [null,1480456060] + ], + "target":"averageSeries(.8192.*.jobs.1.write.iops)" + } +]""" + expected = [[1480455910, 205.345], + [1480455920, 201.59], + [1480455930, 205.76], + [1480455970, 215.655], + [1480455980, 214.16], + [1480455990, 213.57], + [1480456030, 219.37], + [1480456040, 219.28], + [1480456050, 217.75]] + + mock_requests.side_effect = (response, ) + + actual = self.graphdb.fetch_series("workload", "iops", + "write", 0, 600) + self.assertEqual(expected, actual) + def fetch_workloads(self, workload): workloads = [[u'32d31724-fac1-44f3-9033-ca8e00066a36.' u'_warm_up.queue-depth.32.block-size.8192.10-9-15-151', diff --git a/tests/utilities_tests/data_handler_test.py b/tests/utilities_tests/data_handler_test.py index 482b98e..b175c87 100644 --- a/tests/utilities_tests/data_handler_test.py +++ b/tests/utilities_tests/data_handler_test.py @@ -8,22 +8,25 @@ ############################################################################## import os +from storperf.utilities.data_handler import DataHandler import unittest import mock -from storperf.utilities.data_handler import DataHandler - class MockGraphiteDB(object): def __init__(self): self.called = False + self.series = [] def fetch_averages(self, job_id): self.called = True return None + def fetch_series(self, job_id, timeframe): + return self.series + class DataHandlerTest(unittest.TestCase): @@ -40,6 +43,7 @@ class DataHandlerTest(unittest.TestCase): mock.job_id = "1" self.job_db = mock self.pushed = False + self.current_workload = None pass @property @@ -50,8 +54,68 @@ class DataHandlerTest(unittest.TestCase): self.pushed = True pass - def test_not_terminated_report(self): - self.data_handler.data_event(self) + def terminate(self): + self._terminated = True + + @mock.patch("time.time") + @mock.patch.dict(os.environ, {'TEST_DB_URL': 'mock'}) + @mock.patch("storperf.db.graphite_db.GraphiteDB.fetch_series") + def test_lookup_prior_data(self, mock_graphite_db, mock_time): + self._terminated = False + expected = [[1480455910, 205.345], + [1480455920, 201.59], + [1480455930, 205.76], + [1480455970, 215.655], + [1480455980, 214.16], + [1480455990, 213.57], + [1480456030, 219.37], + [1480456040, 219.28], + [1480456050, 217.75]] + mock_graphite_db.return_value = expected + mock_time.return_value = expected[-1][0] + 10 + + self.current_workload = ("%s.%s.queue-depth.%s.block-size.%s" % + ("job_id", + "rw", + 8, + 8192)) + + actual = self.data_handler._lookup_prior_data(self, 'read', 'iops') + self.assertEqual(expected, actual) + + def test_short_sample(self): + series = [[1480455910, 205.345], + [1480455920, 201.59], + [1480455930, 205.76], + [1480455970, 215.655], + [1480455980, 214.16], + [1480455990, 213.57], + [1480456030, 219.37], + [1480456040, 219.28], + [1480456050, 217.75]] + + actual = self.data_handler._evaluate_prior_data(series) + self.assertEqual(False, actual) + + def test_long_not_steady_sample(self): + series = [[4804559100, 205345], + [4804559200, 20159], + [4804559300, 20576], + [4804560300, 21937], + [4804560400, 21928], + [4804560500, 21775]] + actual = self.data_handler._evaluate_prior_data(series) + self.assertEqual(False, actual) + + def test_long_steady_sample(self): + series = [[4804559100, 205.345], + [4804559200, 201.59], + [4804559300, 205.76], + [4804560300, 219.37], + [4804560400, 219.28], + [4804560500, 217.75]] + actual = self.data_handler._evaluate_prior_data(series) + self.assertEqual(True, actual) @mock.patch.dict(os.environ, {'TEST_DB_URL': 'mock'}) @mock.patch("storperf.db.test_results_db.push_results_to_db") @@ -65,12 +129,104 @@ class DataHandlerTest(unittest.TestCase): self.assertEqual(True, self.pushed) @mock.patch.dict(os.environ, {'TEST_DB_URL': 'mock'}) + @mock.patch("time.time") @mock.patch("storperf.db.test_results_db.push_results_to_db") - @mock.patch("storperf.utilities.data_handler.GraphiteDB") - def test_non_terminated_report(self, mock_graphite_db, mock_results_db): + @mock.patch("storperf.db.graphite_db.GraphiteDB.fetch_series") + def test_non_terminated_report(self, mock_graphite_db, mock_results_db, + mock_time): self._terminated = False mock_results_db.side_effect = self.push_results_to_db - mock_graphite_db.side_effect = MockGraphiteDB + series = \ + [[1480455910, 205.345], + [1480455920, 201.59], + [1480455930, 205.76], + [1480455970, 215.655], + [1480455980, 214.16], + [1480455990, 213.57], + [1480456030, 219.37], + [1480456040, 219.28], + [1480456050, 217.75]] + mock_graphite_db.return_value = series + mock_time.return_value = series[-1][0] + 10 + expected_slope = 0.1185333530108134 + expected_range = 17.78 + expected_average = 212.49777777777774 + + self.current_workload = ("%s.%s.queue-depth.%s.block-size.%s" % + ("job_id", + "rw", + 8, + 8192)) self.data_handler.data_event(self) self.assertEqual(False, self.pushed) + self.assertEqual(False, self._terminated) + + self.assertEqual(expected_slope, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['slope']) + self.assertEqual(expected_range, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['range']) + self.assertEqual(expected_average, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['average']) + self.assertEqual(series, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['series']) + + @mock.patch.dict(os.environ, {'TEST_DB_URL': 'mock'}) + @mock.patch("time.time") + @mock.patch("storperf.db.test_results_db.push_results_to_db") + @mock.patch("storperf.db.graphite_db.GraphiteDB.fetch_series") + def test_report_that_causes_termination(self, + mock_graphite_db, + mock_results_db, + mock_time): + self._terminated = False + mock_results_db.side_effect = self.push_results_to_db + series = [[4804559100, 205.345], + [4804559200, 201.59], + [4804559300, 205.76], + [4804560300, 219.37], + [4804560400, 219.28], + [4804560500, 217.75]] + mock_graphite_db.return_value = series + mock_time.return_value = 4804560500 + 10 + + expected_slope = 0.011830471529818998 + expected_range = 17.78 + expected_average = 211.51583333333335 + + self.current_workload = ("%s.%s.queue-depth.%s.block-size.%s" % + ("job_id", + "rw", + 8, + 8192)) + + self.data_handler.data_event(self) + + self.assertEqual(expected_slope, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['slope']) + self.assertEqual(expected_range, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['range']) + self.assertEqual(expected_average, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['average']) + self.assertEqual(series, self.metadata['report_data'] + ['lat.mean'] + ['read'] + ['series']) + self.assertEqual(True, self._terminated) + + self.assertEqual(False, self.pushed) + self.assertEqual(True, self._terminated) diff --git a/tests/utilities_tests/math_slope_test.py b/tests/utilities_tests/math_slope_test.py index 6c05aa4..24d5cd7 100644 --- a/tests/utilities_tests/math_slope_test.py +++ b/tests/utilities_tests/math_slope_test.py @@ -65,3 +65,8 @@ class MathSlopeTest(unittest.TestCase): expected = 1.5 actual = Slope.slope([[0.0, 0], [1, 1], [2, 3]]) self.assertEqual(expected, actual) + + def test_infinte_slope(self): + expected = None + actual = Slope.slope([[1480623510, 1295.87], [1480623520, 1380.79]]) + self.assertEqual(expected, actual) -- cgit 1.2.3-korg