From ff2e2227b28f18ebbc265eee6ee5a50cabacc075 Mon Sep 17 00:00:00 2001 From: Benoit HERARD Date: Fri, 30 Jun 2017 13:30:19 +0200 Subject: [PATCH] Energy monitoring SDK update. add get_current scenario in EnergyRecorder class enable_recording decorator change: If a recording session was existing at startup, restart it at the end, else stop recording Change-Id: I91524824acb60275e0329452b7d7df2346d7884f Signed-off-by: Benoit HERARD --- functest/ci/config_functest.yaml | 2 +- functest/energy/energy.py | 96 ++++++++++++++++++++-- functest/tests/unit/energy/test_functest_energy.py | 48 ++++++++++- 3 files changed, 133 insertions(+), 13 deletions(-) diff --git a/functest/ci/config_functest.yaml b/functest/ci/config_functest.yaml index b93730cdf..1807082d9 100644 --- a/functest/ci/config_functest.yaml +++ b/functest/ci/config_functest.yaml @@ -200,6 +200,6 @@ results: test_db_url: http://testresults.opnfv.org/test/api/v1/results energy_recorder: - api_url: http://161.105.253.100:8888/resources + api_url: http://opnfv.fr:8888/resources api_user: "" api_password: "" diff --git a/functest/energy/energy.py b/functest/energy/energy.py index a20c79926..71b712393 100644 --- a/functest/energy/energy.py +++ b/functest/energy/energy.py @@ -20,6 +20,8 @@ import functest.utils.functest_utils as ft_utils def enable_recording(method): """ + Record energy during method execution. + Decorator to record energy during "method" exection. param method: Method to suround with start and stop @@ -29,10 +31,21 @@ def enable_recording(method): attribute """ def wrapper(*args): - """Wrapper for decorator to handle method arguments.""" + """ + Record energy during method execution (implementation). + + Wrapper for decorator to handle method arguments. + """ + current_scenario = EnergyRecorder.get_current_scenario() EnergyRecorder.start(args[0].case_name) return_value = method(*args) - EnergyRecorder.stop() + if current_scenario is None: + EnergyRecorder.stop() + else: + EnergyRecorder.submit_scenario( + current_scenario["scenario"], + current_scenario["step"] + ) return return_value return wrapper @@ -47,7 +60,7 @@ class EnergyRecorder(object): energy_recorder_api = None # Default initial step - INITIAL_STEP = "starting" + INITIAL_STEP = "running" @staticmethod def load_config(): @@ -92,22 +105,24 @@ class EnergyRecorder(object): } @staticmethod - def start(scenario): + def submit_scenario(scenario, step): """ - Start a recording session for scenario. + Submit a complet scenario definition to Energy recorder API. - param scenario: Starting scenario + param scenario: Scenario name :type scenario: string + param step: Step name + :type step: string """ return_status = True try: - EnergyRecorder.logger.debug("Starting recording") + EnergyRecorder.logger.debug("Submitting scenario") # Ensure that connectyvity settings are loaded EnergyRecorder.load_config() # Create API payload payload = { - "step": EnergyRecorder.INITIAL_STEP, + "step": step, "scenario": scenario } # Call API to start energy recording @@ -120,10 +135,34 @@ class EnergyRecorder(object): } ) if response.status_code != 200: - log_msg = "Error while starting energy recording session\n{}" + log_msg = "Error while submitting scenario\n{}" log_msg = log_msg.format(response.text) EnergyRecorder.logger.info(log_msg) return_status = False + except Exception: # pylint: disable=broad-except + # Default exception handler to ensure that method + # is safe for caller + EnergyRecorder.logger.exception( + "Error while submitting scenarion to energy recorder API" + ) + return_status = False + return return_status + + @staticmethod + def start(scenario): + """ + Start a recording session for scenario. + + param scenario: Starting scenario + :type scenario: string + """ + return_status = True + try: + EnergyRecorder.logger.debug("Starting recording") + return_status = EnergyRecorder.submit_scenario( + scenario, + EnergyRecorder.INITIAL_STEP + ) except Exception: # pylint: disable=broad-except # Default exception handler to ensure that method @@ -201,3 +240,42 @@ class EnergyRecorder(object): ) return_status = False return return_status + + @staticmethod + def get_current_scenario(): + """Get current running scenario (if any, None else).""" + EnergyRecorder.logger.debug("Getting current scenario") + return_value = None + print "In get current" + try: + # Ensure that connectyvity settings are loaded + EnergyRecorder.load_config() + + # Call API get running scenario + response = requests.get( + EnergyRecorder.energy_recorder_api["uri"], + auth=EnergyRecorder.energy_recorder_api["auth"] + ) + if response.status_code == 200: + return_value = json.loads(response.text) + elif response.status_code == 404: + log_msg = "No current running scenario at {}" + log_msg = log_msg.format( + EnergyRecorder.energy_recorder_api["uri"]) + EnergyRecorder.logger.error(log_msg) + print log_msg + return_value = None + else: + log_msg = "Error while getting current scenario\n{}" + log_msg = log_msg.format(response.text) + EnergyRecorder.logger.error(log_msg) + print log_msg + return_value = None + except Exception: # pylint: disable=broad-except + # Default exception handler to ensure that method + # is safe for caller + EnergyRecorder.logger.exception( + "Error while getting current scenario from energy recorder API" + ) + return_value = None + return return_value diff --git a/functest/tests/unit/energy/test_functest_energy.py b/functest/tests/unit/energy/test_functest_energy.py index 6387b97ba..177788bc4 100644 --- a/functest/tests/unit/energy/test_functest_energy.py +++ b/functest/tests/unit/energy/test_functest_energy.py @@ -1,5 +1,8 @@ #!/usr/bin/env python +# -*- coding: UTF-8 -*- +# Copyright (c) 2017 Orange and others. +# # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at @@ -16,8 +19,11 @@ from functest.energy.energy import EnergyRecorder import functest.energy.energy as energy -CASE_NAME = "UNIT_test_CASE" -STEP_NAME = "UNIT_test_STEP" +CASE_NAME = "UNIT_TEST_CASE" +STEP_NAME = "UNIT_TEST_STEP" + +PREVIOUS_SCENARIO = "previous_scenario" +PREVIOUS_STEP = "previous_step" class MockHttpResponse(object): # pylint: disable=too-few-public-methods @@ -197,6 +203,8 @@ class EnergyRecorderTest(unittest.TestCase): """Call with to energy recorder decorators.""" raise Exception(self.exception_message_to_preserve) + @mock.patch("functest.energy.energy.EnergyRecorder.get_current_scenario", + return_value=None) @mock.patch("functest.energy.energy.EnergyRecorder") @mock.patch("functest.utils.functest_utils.get_pod_name", return_value="MOCK_POD") @@ -205,13 +213,34 @@ class EnergyRecorderTest(unittest.TestCase): def test_decorators(self, loader_mock=None, pod_mock=None, - recorder_mock=None): + recorder_mock=None, + cur_scenario_mock=None): """Test energy module decorators.""" self.__decorated_method() calls = [mock.call.start(self.case_name), mock.call.stop()] recorder_mock.assert_has_calls(calls) + @mock.patch("functest.energy.energy.EnergyRecorder.get_current_scenario", + return_value={"scenario": PREVIOUS_SCENARIO, + "step": PREVIOUS_STEP}) + @mock.patch("functest.energy.energy.EnergyRecorder") + @mock.patch("functest.utils.functest_utils.get_pod_name", + return_value="MOCK_POD") + @mock.patch("functest.utils.functest_utils.get_functest_config", + side_effect=config_loader_mock) + def test_decorators_with_previous(self, + loader_mock=None, + pod_mock=None, + recorder_mock=None, + cur_scenario_mock=None): + """Test energy module decorators.""" + self.__decorated_method() + calls = [mock.call.start(self.case_name), + mock.call.submit_scenario(PREVIOUS_SCENARIO, + PREVIOUS_STEP)] + recorder_mock.assert_has_calls(calls) + def test_decorator_preserve_return(self): """Test that decorator preserve method returned value.""" self.test_load_config() @@ -270,6 +299,19 @@ class EnergyRecorderTest(unittest.TestCase): EnergyRecorder.load_config() self.assertEquals(EnergyRecorder.energy_recorder_api, None) + @mock.patch("functest.utils.functest_utils.get_functest_config", + return_value=None) + @mock.patch("functest.utils.functest_utils.get_pod_name", + return_value="MOCK_POD") + @mock.patch('functest.energy.energy.requests.get', + return_value=RECORDER_OK) + def test_get_current_scenario(self, loader_mock=None, + pod_mock=None, get_mock=None): + """Test get_current_scenario.""" + self.test_load_config() + scenario = EnergyRecorder.get_current_scenario() + self.assertTrue(scenario is not None) + if __name__ == "__main__": logging.disable(logging.CRITICAL) -- 2.16.6