Energy monitoring SDK update. 97/36797/3
authorBenoit HERARD <benoit.herard@orange.com>
Fri, 30 Jun 2017 11:30:19 +0000 (13:30 +0200)
committerJose Lausuch <jose.lausuch@ericsson.com>
Sat, 1 Jul 2017 08:28:19 +0000 (08:28 +0000)
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 <benoit.herard@orange.com>
functest/ci/config_functest.yaml
functest/energy/energy.py
functest/tests/unit/energy/test_functest_energy.py

index b93730c..1807082 100644 (file)
@@ -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: ""
index a20c799..71b7123 100644 (file)
@@ -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
index 6387b97..177788b 100644 (file)
@@ -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)