Repository: Azure/WALinuxAgent
Pull request #1731 (2019-12-11 03:14:37)

Fix upgrade sequence when update command fails
<!-- DO NOT DELETE THIS TEMPLATE -->

## Description

Today, during an extension upgrade, if the update command of the new extension fails, the new extension will be marked as Failed and on the next goal state we would directly call enable on the new version instead of calling download, initialize, and update beforehand due to [this check](https://github.com/Azure/WALinuxAgent/blob/develop/azurelinuxagent/ga/exthandlers.py#L487). This PR fixes the condition by including the `FailedUpgrade` state, ensuring we don't skip any steps in the upgrade scenario in subsequent goal states.

We need to keep the failed (new) version on disk in order to keep reporting its failed status. Since we don't clean up the failed extension, this means that we won't re-download it on the next goal state, but re-use the existing zip on disk. The old extension is also present on disk and disabled. When uninstall is called, the old version is uninstalled and removed. The new version's zip still persists (and is in a failed state). Improvements on this clean up logic can be addressed in a separate PR.

<!--
Please add an informative description that covers that changes made by the pull request. 
This checklist is used to make sure that common issues in a pull request are addressed.
This will expedite the process of getting your pull request merged and avoid extra work on your part to fix issues discovered during the review process.
-->

---

### PR information
- [ ] The title of the PR is clear and informative.
- [ ] There are a small number of commits, each of which has an informative message. This means that previously merged commits do not appear in the history of the PR. For information on cleaning up the commits in your pull request, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md).
- [ ] Except for special cases involving multiple contributors, the PR is started from a fork of the main repository, not a branch.
- [ ] If applicable, the PR references the bug/issue that it fixes in the description.
- [ ] New Unit tests were added for the changes made and Travis.CI is passing.

### Quality of Code and Contribution Guidelines
- [ ] I have read the [contribution guidelines](https://github.com/Azure/WALinuxAgent/blob/master/.github/CONTRIBUTING.md).

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/azure/walinuxagent/1731)
<!-- Reviewable:end -->



Patch:
diff --git a/README.md b/README.md
index 80468e39..7533c59c 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,12 @@
 # Microsoft Azure Linux Agent
 
-## Develop branch status
+## Master branch status
 
 [![Travis CI](https://travis-ci.org/Azure/WALinuxAgent.svg?branch=develop)](https://travis-ci.org/Azure/WALinuxAgent/branches)
 [![CodeCov](https://codecov.io/gh/Azure/WALinusAgent/branch/develop/graph/badge.svg)](https://codecov.io/gh/Azure/WALinuxAgent/branch/develop)
 
 Each badge below represents our basic validation tests for an image, which are executed several times each day. These include provisioning, user account, disk, extension and networking scenarios.
 
-Note: These badges represent testing to our develop branch which might not be stable. For a stable build please use master branch instead. 
-
 Image | Status |
 ------|--------|
 Canonical UbuntuServer 14.04.5-LTS|![badge](https://dcrbadges.blob.core.windows.net/scenarios/Canonical_UbuntuServer_14.04.5-LTS__agent--bvt.svg)
diff --git a/azurelinuxagent/common/cgroup.py b/azurelinuxagent/common/cgroup.py
index 1f940b5f..858fa9da 100644
--- a/azurelinuxagent/common/cgroup.py
+++ b/azurelinuxagent/common/cgroup.py
@@ -61,9 +61,13 @@ class CGroup(object):
         :return: Entire contents of the file
         :rtype: str
         """
+
         parameter_file = self._get_cgroup_file(file_name)
 
-        return fileutil.read_file(parameter_file)
+        try:
+            return fileutil.read_file(parameter_file)
+        except Exception:
+            raise
 
     def _get_parameters(self, parameter_name, first_line_only=False):
         """
@@ -114,78 +118,76 @@ class CGroup(object):
 
 class CpuCgroup(CGroup):
     def __init__(self, name, cgroup_path):
+        """
+        Initialize _data collection for the Cpu controller. User must call update() before attempting to get
+        any useful metrics.
+
+        :return: CpuCgroup
+        """
         super(CpuCgroup, self).__init__(name, cgroup_path, "cpu")
 
         self._osutil = get_osutil()
-        self._previous_cgroup_cpu = None
-        self._previous_system_cpu = None
-        self._current_cgroup_cpu = None
-        self._current_system_cpu = None
+        self._current_cpu_total = 0
+        self._previous_cpu_total = 0
+        self._current_system_cpu = self._osutil.get_total_cpu_ticks_since_boot()
+        self._previous_system_cpu = 0
 
     def __str__(self):
         return "cgroup: Name: {0}, cgroup_path: {1}; Controller: {2}".format(
             self.name, self.path, self.controller
         )
 
-    def _get_cpu_ticks(self, allow_no_such_file_or_directory_error=False):
+    def _get_current_cpu_total(self):
         """
-        Returns the number of USER_HZ of CPU time (user and system) consumed by this cgroup.
+        Compute the number of USER_HZ of CPU time (user and system) consumed by this cgroup since boot.
 
-        If allow_no_such_file_or_directory_error is set to True and cpuacct.stat does not exist the function
-        returns 0; this is useful when the function can be called before the cgroup has been created.
+        :return: int
         """
+        cpu_total = 0
         try:
             cpu_stat = self._get_file_contents('cpuacct.stat')
         except Exception as e:
-            if not isinstance(e, (IOError, OSError)) or e.errno != errno.ENOENT:
-                raise CGroupsException("Failed to read cpuacct.stat: {0}".format(ustr(e)))
-            if not allow_no_such_file_or_directory_error:
+            if isinstance(e, (IOError, OSError)) and e.errno == errno.ENOENT:
                 raise e
-            cpu_stat = None
-
-        cpu_ticks = 0
-
-        if cpu_stat is not None:
-            match = re_user_system_times.match(cpu_stat)
-            if not match:
-                raise CGroupsException("The contents of {0} are invalid: {1}".format(self._get_cgroup_file('cpuacct.stat'), cpu_stat))
-            cpu_ticks = int(match.groups()[0]) + int(match.groups()[1])
-
-        return cpu_ticks
+            raise CGroupsException("Exception while attempting to read {0}".format("cpuacct.stat"), e)
 
-    def _cpu_usage_initialized(self):
-        return self._current_cgroup_cpu is not None and self._current_system_cpu is not None
+        if cpu_stat:
+            m = re_user_system_times.match(cpu_stat)
+            if m:
+                cpu_total = int(m.groups()[0]) + int(m.groups()[1])
+        return cpu_total
 
-    def initialize_cpu_usage(self):
+    def _update_cpu_data(self):
         """
-        Sets the initial values of CPU usage. This function must be invoked before calling get_cpu_usage().
+        Update all raw _data required to compute metrics of interest. The intent is to call update() once, then
+        call the various get_*() methods which use this _data, which we've collected exactly once.
         """
-        if self._cpu_usage_initialized():
-            raise CGroupsException("initialize_cpu_usage() should be invoked only once")
-        self._current_cgroup_cpu = self._get_cpu_ticks(allow_no_such_file_or_directory_error=True)
+        self._previous_cpu_total = self._current_cpu_total
+        self._previous_system_cpu = self._current_system_cpu
+        self._current_cpu_total = self._get_current_cpu_total()
         self._current_system_cpu = self._osutil.get_total_cpu_ticks_since_boot()
 
-    def get_cpu_usage(self):
+    def _get_cpu_percent(self):
         """
-        Computes the CPU used by the cgroup since the last call to this function.
-
-        The usage is measured as a percentage of utilization of all cores in the system. For example,
-        using 1 core at 100% on a 4-core system would be reported as 25%.
+        Compute the percent CPU time used by this cgroup over the elapsed time since the last time this instance was
+        update()ed.  If the cgroup fully consumed 2 cores on a 4 core system, return 200.
 
-        NOTE: initialize_cpu_usage() must be invoked before calling get_cpu_usage()
+        :return: CPU usage in percent of a single core
+        :rtype: float
         """
-        if not self._cpu_usage_initialized():
-            raise CGroupsException("initialize_cpu_usage() must be invoked before the first call to get_cpu_usage()")
+        cpu_delta = self._current_cpu_total - self._previous_cpu_total
+        system_delta = max(1, self._current_system_cpu - self._previous_system_cpu)
 
-        self._previous_cgroup_cpu = self._current_cgroup_cpu
-        self._previous_system_cpu = self._current_system_cpu
-        self._current_cgroup_cpu = self._get_cpu_ticks()
-        self._current_system_cpu = self._osutil.get_total_cpu_ticks_since_boot()
+        return round(float(cpu_delta * self._osutil.get_processor_cores() * 100) / float(system_delta), 3)
 
-        cgroup_delta = self._current_cgroup_cpu - self._previous_cgroup_cpu
-        system_delta = max(1, self._current_system_cpu - self._previous_system_cpu)
+    def get_cpu_usage(self):
+        """
+        Collects and return the cpu usage.
 
-        return round(100.0 * float(cgroup_delta) / float(system_delta), 3)
+        :rtype: float
+        """
+        self._update_cpu_data()
+        return self._get_cpu_percent()
 
 
 class MemoryCgroup(CGroup):
diff --git a/azurelinuxagent/common/cgroupstelemetry.py b/azurelinuxagent/common/cgroupstelemetry.py
index 3d136520..dcc586a3 100644
--- a/azurelinuxagent/common/cgroupstelemetry.py
+++ b/azurelinuxagent/common/cgroupstelemetry.py
@@ -19,7 +19,6 @@ from collections import namedtuple
 from datetime import datetime as dt
 
 from azurelinuxagent.common import logger
-from azurelinuxagent.common.cgroup import CpuCgroup
 from azurelinuxagent.common.exception import CGroupsException
 from azurelinuxagent.common.future import ustr
 
@@ -69,10 +68,6 @@ class CGroupsTelemetry(object):
         """
         Adds the given item to the dictionary of tracked cgroups
         """
-        if isinstance(cgroup, CpuCgroup):
-            # set the current cpu usage
-            cgroup.initialize_cpu_usage()
-
         with CGroupsTelemetry._rlock:
             if not CGroupsTelemetry.is_tracked(cgroup.path):
                 CGroupsTelemetry._tracked.append(cgroup)
diff --git a/azurelinuxagent/common/osutil/default.py b/azurelinuxagent/common/osutil/default.py
index 90a6e739..b99bca43 100644
--- a/azurelinuxagent/common/osutil/default.py
+++ b/azurelinuxagent/common/osutil/default.py
@@ -1354,7 +1354,7 @@ class DefaultOSUtil(object):
         if proc_stat is not None:
             for line in proc_stat.splitlines():
                 if ALL_CPUS_REGEX.match(line):
-                    system_cpu = sum(int(i) for i in line.split()[1:8])  # see "man proc" for a description of these fields
+                    system_cpu = sum(int(i) for i in line.split()[1:7])
                     break
         return system_cpu
 
diff --git a/azurelinuxagent/daemon/resourcedisk/default.py b/azurelinuxagent/daemon/resourcedisk/default.py
index 35ddfb4e..5ed14b01 100644
--- a/azurelinuxagent/daemon/resourcedisk/default.py
+++ b/azurelinuxagent/daemon/resourcedisk/default.py
@@ -249,20 +249,14 @@ class ResourceDiskHandler(object):
 
         return err_code, output
 
-    def get_mount_string(self, mount_options, partition, mount_point):
+    @staticmethod
+    def get_mount_string(mount_options, partition, mount_point):
         if mount_options is not None:
-            return 'mount -t {0} -o {1} {2} {3}'.format(
-                self.fs,
-                mount_options,
-                partition,
-                mount_point
-            )
+            return 'mount -o {0} {1} {2}'.format(mount_options,
+                                                 partition,
+                                                 mount_point)
         else:
-            return 'mount -t {0} {1} {2}'.format(
-                self.fs,
-                partition,
-                mount_point
-            )
+            return 'mount {0} {1}'.format(partition, mount_point)
 
     @staticmethod
     def check_existing_swap_file(swapfile, swaplist, size):
diff --git a/azurelinuxagent/ga/exthandlers.py b/azurelinuxagent/ga/exthandlers.py
index 419f8e8c..2a9866a6 100644
--- a/azurelinuxagent/ga/exthandlers.py
+++ b/azurelinuxagent/ga/exthandlers.py
@@ -203,7 +203,7 @@ class ExtHandlerState(object):
     NotInstalled = "NotInstalled"
     Installed = "Installed"
     Enabled = "Enabled"
-    Failed = "Failed"
+    FailedUpgrade = "FailedUpgrade"
 
 
 def get_exthandlers_handler():
@@ -484,7 +484,9 @@ class ExtHandlersHandler(object):
         handler_state = ext_handler_i.get_handler_state()
         ext_handler_i.logger.info("[Enable] current handler state is: {0}",
                                   handler_state.lower())
-        if handler_state == ExtHandlerState.NotInstalled:
+        # We go through the entire process of downloading and initializing the extension if it's either a fresh
+        # extension or if it's a retry of a previously failed upgrade.
+        if handler_state == ExtHandlerState.NotInstalled or handler_state == ExtHandlerState.FailedUpgrade:
             ext_handler_i.set_handler_state(ExtHandlerState.NotInstalled)
             ext_handler_i.download()
             ext_handler_i.initialize()
@@ -764,17 +766,17 @@ class ExtHandlerInstance(object):
         return FlexibleVersion(self_version) != FlexibleVersion(other_version)
 
     def get_installed_ext_handler(self):
-        lastest_version = self.get_installed_version()
-        if lastest_version is None:
+        latest_version = self.get_installed_version()
+        if latest_version is None:
             return None
 
         installed_handler = ExtHandler()
         set_properties("ExtHandler", installed_handler, get_properties(self.ext_handler))
-        installed_handler.properties.version = lastest_version
+        installed_handler.properties.version = latest_version
         return ExtHandlerInstance(installed_handler, self.protocol)
 
     def get_installed_version(self):
-        lastest_version = None
+        latest_version = None
 
         for path in glob.iglob(os.path.join(conf.get_lib_dir(), self.ext_handler.name + "-*")):
             if not os.path.isdir(path):
@@ -784,17 +786,16 @@ class ExtHandlerInstance(object):
             version_from_path = FlexibleVersion(path[separator + 1:])
             state_path = os.path.join(path, 'config', 'HandlerState')
 
-            if not os.path.exists(state_path) or \
-                    fileutil.read_file(state_path) == \
-                    ExtHandlerState.NotInstalled:
-                logger.verbose("Ignoring version of uninstalled extension: "
+            if not os.path.exists(state_path) or fileutil.read_file(state_path) == ExtHandlerState.NotInstalled \
+                    or fileutil.read_file(state_path) == ExtHandlerState.FailedUpgrade:
+                logger.verbose("Ignoring version of uninstalled or failed extension: "
                                "{0}".format(path))
                 continue
 
-            if lastest_version is None or lastest_version < version_from_path:
-                lastest_version = version_from_path
+            if latest_version is None or latest_version < version_from_path:
+                latest_version = version_from_path
 
-        return str(lastest_version) if lastest_version is not None else None
+        return str(latest_version) if latest_version is not None else None
 
     def copy_status_files(self, old_ext_handler_i):
         self.logger.info("Copy status files from old plugin to new")
@@ -1033,8 +1034,8 @@ class ExtHandlerInstance(object):
                                 extension_error_code=ExtensionErrorCodes.PluginUpdateProcessingFailed,
                                 env=env)
         except ExtensionError:
-            # prevent the handler update from being retried
-            self.set_handler_state(ExtHandlerState.Failed)
+            # Mark the handler as Failed so we don't clean it up and can keep reporting its status
+            self.set_handler_state(ExtHandlerState.FailedUpgrade)
             raise
 
     def update_with_install(self, uninstall_exit_code=None):


Test patch:
diff --git a/tests/common/test_cgroupconfigurator.py b/tests/common/test_cgroupconfigurator.py
index 0f4e9108..fcc816cf 100644
--- a/tests/common/test_cgroupconfigurator.py
+++ b/tests/common/test_cgroupconfigurator.py
@@ -203,18 +203,15 @@ class CGroupConfiguratorTestCase(AgentTestCase):
             self.assertEqual(mock_start_extension_command.call_count, 1)
 
     def test_start_extension_command_should_start_tracking_the_extension_cgroups(self):
-        # CPU usage is initialized when we begin tracking a CPU cgroup; since this test does not retrieve the
-        # CPU usage, there is no need for initialization
-        with patch("azurelinuxagent.common.cgroup.CpuCgroup.initialize_cpu_usage"):
-            CGroupConfigurator.get_instance().start_extension_command(
-                extension_name="Microsoft.Compute.TestExtension-1.2.3",
-                command="date",
-                timeout=300,
-                shell=False,
-                cwd=self.tmp_dir,
-                env={},
-                stdout=subprocess.PIPE,
-                stderr=subprocess.PIPE)
+        CGroupConfigurator.get_instance().start_extension_command(
+            extension_name="Microsoft.Compute.TestExtension-1.2.3",
+            command="date",
+            timeout=300,
+            shell=False,
+            cwd=self.tmp_dir,
+            env={},
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE)
 
         self.assertTrue(CGroupsTelemetry.is_tracked(os.path.join(
             self.cgroups_file_system_root, "cpu", "walinuxagent.extensions/Microsoft.Compute.TestExtension_1.2.3")))
diff --git a/tests/common/test_cgroups.py b/tests/common/test_cgroups.py
index 6827fb8b..b33bc94f 100644
--- a/tests/common/test_cgroups.py
+++ b/tests/common/test_cgroups.py
@@ -17,7 +17,6 @@
 
 from __future__ import print_function
 
-import errno
 import os
 import random
 
@@ -47,7 +46,10 @@ class TestCGroup(AgentTestCase):
         with open(os.path.join(data_dir, "cgroups", "memory_mount", "tasks"), mode="wb") as tasks:
             tasks.truncate(0)
 
-    def test_correct_creation(self):
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_correct_creation(self, *_):
         test_cgroup = CGroup.create("dummy_path", "cpu", "test_extension")
         self.assertIsInstance(test_cgroup, CpuCgroup)
         self.assertEqual(test_cgroup.controller, "cpu")
@@ -60,7 +62,10 @@ class TestCGroup(AgentTestCase):
         self.assertEqual(test_cgroup.path, "dummy_path")
         self.assertEqual(test_cgroup.name, "test_extension")
 
-    def test_is_active(self):
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_is_active(self, *_):
         test_cgroup = CGroup.create(os.path.join(data_dir, "cgroups", "cpu_mount"), "cpu", "test_extension")
         self.assertEqual(False, test_cgroup.is_active())
 
@@ -77,8 +82,11 @@ class TestCGroup(AgentTestCase):
 
         self.assertEqual(True, test_cgroup.is_active())
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
-    def test_is_active_file_not_present(self, patch_periodic_warn):
+    def test_is_active_file_not_present(self, patch_periodic_warn, *_):
         test_cgroup = CGroup.create(os.path.join(data_dir, "cgroups", "not_cpu_mount"), "cpu", "test_extension")
         self.assertEqual(False, test_cgroup.is_active())
 
@@ -87,8 +95,11 @@ class TestCGroup(AgentTestCase):
 
         self.assertEqual(0, patch_periodic_warn.call_count)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
-    def test_is_active_incorrect_file(self, patch_periodic_warn):
+    def test_is_active_incorrect_file(self, patch_periodic_warn, *_):
         test_cgroup = CGroup.create(os.path.join(data_dir, "cgroups", "cpu_mount", "tasks"), "cpu", "test_extension")
         self.assertEqual(False, test_cgroup.is_active())
         self.assertEqual(1, patch_periodic_warn.call_count)
@@ -99,115 +110,49 @@ class TestCGroup(AgentTestCase):
 
 
 class TestCpuCgroup(AgentTestCase):
-    @classmethod
-    def setUpClass(cls):
-        AgentTestCase.setUpClass()
-
-        original_read_file = fileutil.read_file
-
-        #
-        # Tests that need to mock the contents of /proc/stat or */cpuacct/stat can set this map from
-        # the file that needs to be mocked to the mock file (each test starts with an empty map). If
-        # an Exception is given instead of a path, the exception is raised
-        #
-        cls.mock_read_file_map = {}
-
-        def mock_read_file(filepath, **args):
-            if filepath in cls.mock_read_file_map:
-                mapped_value = cls.mock_read_file_map[filepath]
-                if isinstance(mapped_value, Exception):
-                    raise mapped_value
-                filepath = mapped_value
-            return original_read_file(filepath, **args)
-
-        cls.mock_read_file = patch("azurelinuxagent.common.utils.fileutil.read_file", side_effect=mock_read_file)
-        cls.mock_read_file.start()
-
-    @classmethod
-    def tearDownClass(cls):
-        cls.mock_read_file.stop()
-        AgentTestCase.tearDownClass()
-
     def setUp(self):
         AgentTestCase.setUp(self)
-        TestCpuCgroup.mock_read_file_map.clear()
-
-    def test_initialize_cpu_usage_should_set_current_cpu_usage(self):
-        cgroup = CpuCgroup("test", "/sys/fs/cgroup/cpu/system.slice/test")
-
-        TestCpuCgroup.mock_read_file_map = {
-            "/proc/stat": os.path.join(data_dir, "cgroups", "proc_stat_t0"),
-            os.path.join(cgroup.path, "cpuacct.stat"): os.path.join(data_dir, "cgroups", "cpuacct.stat_t0")
-        }
-
-        cgroup.initialize_cpu_usage()
-
-        self.assertEquals(cgroup._current_cgroup_cpu, 63763)
-        self.assertEquals(cgroup._current_system_cpu, 5496872)
-
-    def test_get_cpu_usage_should_return_the_cpu_usage_since_its_last_invocation(self):
-        cgroup = CpuCgroup("test", "/sys/fs/cgroup/cpu/system.slice/test")
-
-        TestCpuCgroup.mock_read_file_map = {
-            "/proc/stat": os.path.join(data_dir, "cgroups", "proc_stat_t0"),
-            os.path.join(cgroup.path, "cpuacct.stat"): os.path.join(data_dir, "cgroups", "cpuacct.stat_t0")
-        }
-
-        cgroup.initialize_cpu_usage()
-
-        TestCpuCgroup.mock_read_file_map = {
-            "/proc/stat": os.path.join(data_dir, "cgroups", "proc_stat_t1"),
-            os.path.join(cgroup.path, "cpuacct.stat"): os.path.join(data_dir, "cgroups", "cpuacct.stat_t1")
-        }
-
-        cpu_usage = cgroup.get_cpu_usage()
-
-        self.assertEquals(cpu_usage, 0.031)
-
-        TestCpuCgroup.mock_read_file_map = {
-            "/proc/stat": os.path.join(data_dir, "cgroups", "proc_stat_t2"),
-            os.path.join(cgroup.path, "cpuacct.stat"): os.path.join(data_dir, "cgroups", "cpuacct.stat_t2")
-        }
-
-        cpu_usage = cgroup.get_cpu_usage()
-
-        self.assertEquals(cpu_usage, 0.045)
-
-    def test_initialie_cpu_usage_should_set_the_cgroup_usage_to_0_when_the_cgroup_does_not_exist(self):
-        cgroup = CpuCgroup("test", "/sys/fs/cgroup/cpu/system.slice/test")
-
-        io_error_2 = IOError()
-        io_error_2.errno = errno.ENOENT  # "No such directory"
-
-        TestCpuCgroup.mock_read_file_map = {
-            "/proc/stat": os.path.join(data_dir, "cgroups", "proc_stat_t0"),
-            os.path.join(cgroup.path, "cpuacct.stat"): io_error_2
-        }
 
-        cgroup.initialize_cpu_usage()
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_cpu_cgroup_create(self, patch_get_proc_stat):
+        patch_get_proc_stat.return_value = fileutil.read_file(os.path.join(data_dir, "cgroups", "dummy_proc_stat"))
+        test_cpu_cg = CpuCgroup("test_extension", "dummy_path")
 
-        self.assertEquals(cgroup._current_cgroup_cpu, 0)
-        self.assertEquals(cgroup._current_system_cpu, 5496872)  # check the system usage just for test sanity
+        self.assertEqual(398488, test_cpu_cg._current_system_cpu)
+        self.assertEqual(0, test_cpu_cg._current_cpu_total)
+        self.assertEqual(0, test_cpu_cg._previous_cpu_total)
+        self.assertEqual(0, test_cpu_cg._previous_system_cpu)
 
+        self.assertEqual("cpu", test_cpu_cg.controller)
 
-    def test_initialize_cpu_usage_should_raise_an_exception_when_called_more_than_once(self):
-        cgroup = CpuCgroup("test", "/sys/fs/cgroup/cpu/system.slice/test")
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_processor_cores", return_value=1)
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_get_cpu_usage(self, patch_get_proc_stat, *args):
+        patch_get_proc_stat.return_value = fileutil.read_file(os.path.join(data_dir, "cgroups", "dummy_proc_stat"))
+        test_cpu_cg = CpuCgroup("test_extension", os.path.join(data_dir, "cgroups", "cpu_mount"))
 
-        TestCpuCgroup.mock_read_file_map = {
-            "/proc/stat": os.path.join(data_dir, "cgroups", "proc_stat_t0"),
-            os.path.join(cgroup.path, "cpuacct.stat"): os.path.join(data_dir, "cgroups", "cpuacct.stat_t0")
-        }
+        # Mocking CPU consumption
+        patch_get_proc_stat.return_value = fileutil.read_file(os.path.join(data_dir, "cgroups",
+                                                                           "dummy_proc_stat_updated"))
 
-        cgroup.initialize_cpu_usage()
+        cpu_usage = test_cpu_cg.get_cpu_usage()
 
-        with self.assertRaises(CGroupsException):
-            cgroup.initialize_cpu_usage()
+        self.assertEqual(5.114, cpu_usage)
 
-    def test_get_cpu_usage_should_raise_an_exception_when_initialize_cpu_usage_has_not_been_invoked(self):
-        cgroup = CpuCgroup("test", "/sys/fs/cgroup/cpu/system.slice/test")
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    def test_get_current_cpu_total_exception_handling(self, *_):
+        test_cpu_cg = CpuCgroup("test_extension", "dummy_path")
+        self.assertRaises(IOError, test_cpu_cg._get_current_cpu_total)
 
-        with self.assertRaises(CGroupsException):
-            cpu_usage = cgroup.get_cpu_usage()
+        # Trying to raise ERRNO 20.
+        test_cpu_cg = CpuCgroup("test_extension", os.path.join(data_dir, "cgroups", "cpu_mount", "cpuacct.stat"))
+        self.assertRaises(CGroupsException, test_cpu_cg._get_current_cpu_total)
 
 
 class TestMemoryCgroup(AgentTestCase):
@@ -231,4 +176,4 @@ class TestMemoryCgroup(AgentTestCase):
         self.assertEqual(0, memory_usage)
 
         max_memory_usage = test_mem_cg.get_max_memory_usage()
-        self.assertEqual(0, max_memory_usage)
+        self.assertEqual(0, max_memory_usage)
\ No newline at end of file
diff --git a/tests/common/test_cgroupstelemetry.py b/tests/common/test_cgroupstelemetry.py
index c6d14d48..e53b08cc 100644
--- a/tests/common/test_cgroupstelemetry.py
+++ b/tests/common/test_cgroupstelemetry.py
@@ -24,11 +24,10 @@ from azurelinuxagent.common.cgroupconfigurator import CGroupConfigurator
 from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry, Metric
 from azurelinuxagent.common.osutil.default import BASE_CGROUPS, DefaultOSUtil
 from azurelinuxagent.common.protocol.restapi import ExtHandlerProperties, ExtHandler
-from azurelinuxagent.common.utils import fileutil
 from azurelinuxagent.ga.exthandlers import ExtHandlerInstance
 from nose.plugins.attrib import attr
 from tests.tools import AgentTestCase, skip_if_predicate_false, skip_if_predicate_true, \
-                        are_cgroups_enabled, is_trusty_in_travis, i_am_root, data_dir, patch
+                        are_cgroups_enabled, is_trusty_in_travis, i_am_root, patch
 
 
 def raise_ioerror(*_):
@@ -78,28 +77,6 @@ def make_new_cgroup(name="test-cgroup"):
 
 
 class TestCGroupsTelemetry(AgentTestCase):
-    @classmethod
-    def setUpClass(cls):
-        AgentTestCase.setUpClass()
-
-        # CPU Cgroups compute usage based on /proc/stat and /sys/fs/cgroup/.../cpuacct.stat; use mock data for those files
-        original_read_file = fileutil.read_file
-
-        def mock_read_file(filepath, **args):
-            if filepath == "/proc/stat":
-                filepath = os.path.join(data_dir, "cgroups", "proc_stat_t0")
-            elif filepath.endswith("/cpuacct.stat"):
-                filepath = os.path.join(data_dir, "cgroups", "cpuacct.stat_t0")
-            return original_read_file(filepath, **args)
-
-        cls._mock_read_cpu_cgroup_file = patch("azurelinuxagent.common.utils.fileutil.read_file", side_effect=mock_read_file)
-        cls._mock_read_cpu_cgroup_file.start()
-
-    @classmethod
-    def tearDownClass(cls):
-        cls._mock_read_cpu_cgroup_file.stop()
-        AgentTestCase.tearDownClass()
-
     def setUp(self):
         AgentTestCase.setUp(self)
         CGroupsTelemetry.reset()
@@ -127,6 +104,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                 elif metric.counter == "Max Memory Usage":
                     self.assertEqual(metric.value, max_memory_metric_value)
 
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_telemetry_polling_with_active_cgroups(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
@@ -139,7 +118,7 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage") as patch_get_memory_max_usage:
             with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage") as patch_get_memory_usage:
-                with patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage") as patch_get_cpu_usage:
+                with patch("azurelinuxagent.common.cgroup.CpuCgroup._get_cpu_percent") as patch_get_cpu_percent:
                     with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
                         patch_is_active.return_value = True
 
@@ -147,7 +126,7 @@ class TestCGroupsTelemetry(AgentTestCase):
                         current_memory = 209715200
                         current_max_memory = 471859200
 
-                        patch_get_cpu_usage.return_value = current_cpu
+                        patch_get_cpu_percent.return_value = current_cpu
                         patch_get_memory_usage.return_value = current_memory  # example 200 MB
                         patch_get_memory_max_usage.return_value = current_max_memory  # example 450 MB
 
@@ -168,6 +147,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                         self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), num_extensions)
                         self._assert_cgroup_metrics_equal([], [], [])
 
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_telemetry_polling_with_inactive_cgroups(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
@@ -180,7 +161,7 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage") as patch_get_memory_max_usage:
             with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage") as patch_get_memory_usage:
-                with patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage") as patch_get_cpu_usage:
+                with patch("azurelinuxagent.common.cgroup.CpuCgroup._get_cpu_percent") as patch_get_cpu_percent:
                     with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
                         patch_is_active.return_value = False
 
@@ -190,7 +171,7 @@ class TestCGroupsTelemetry(AgentTestCase):
                         current_memory = 209715200
                         current_max_memory = 471859200
 
-                        patch_get_cpu_usage.return_value = current_cpu
+                        patch_get_cpu_percent.return_value = current_cpu
                         patch_get_memory_usage.return_value = current_memory  # example 200 MB
                         patch_get_memory_max_usage.return_value = current_max_memory  # example 450 MB
 
@@ -217,6 +198,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                         self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), no_extensions_expected)
                         self._assert_cgroup_metrics_equal([], [], [])
 
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_telemetry_polling_with_changing_cgroups_state(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
@@ -229,7 +212,7 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage") as patch_get_memory_max_usage:
             with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage") as patch_get_memory_usage:
-                with patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage") as patch_get_cpu_usage:
+                with patch("azurelinuxagent.common.cgroup.CpuCgroup._get_cpu_percent") as patch_get_cpu_percent:
                     with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
                         patch_is_active.return_value = True
 
@@ -240,7 +223,7 @@ class TestCGroupsTelemetry(AgentTestCase):
                         current_memory = 209715200
                         current_max_memory = 471859200
 
-                        patch_get_cpu_usage.return_value = current_cpu
+                        patch_get_cpu_percent.return_value = current_cpu
                         patch_get_memory_usage.return_value = current_memory  # example 200 MB
                         patch_get_memory_max_usage.return_value = current_max_memory  # example 450 MB
 
@@ -274,8 +257,13 @@ class TestCGroupsTelemetry(AgentTestCase):
                         self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), no_extensions_expected)
                         self._assert_cgroup_metrics_equal([], [], [])
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
-    def test_telemetry_polling_to_not_generate_transient_logs_ioerror_file_not_found(self, patch_periodic_warn):
+    @patch("azurelinuxagent.common.utils.fileutil.read_file")
+    def test_telemetry_polling_to_not_generate_transient_logs_ioerror_file_not_found(self, mock_read_file,
+                                                                                     patch_periodic_warn, *args):
         num_extensions = 1
         for i in range(num_extensions):
             dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
@@ -290,15 +278,20 @@ class TestCGroupsTelemetry(AgentTestCase):
         # Not expecting logs present for io_error with errno=errno.ENOENT
         io_error_2 = IOError()
         io_error_2.errno = errno.ENOENT
+        mock_read_file.side_effect = io_error_2
 
-        with patch("azurelinuxagent.common.utils.fileutil.read_file", side_effect=io_error_2):
-            poll_count = 1
-            for data_count in range(poll_count, 10):
-                CGroupsTelemetry.poll_all_tracked()
-                self.assertEqual(0, patch_periodic_warn.call_count)
+        poll_count = 1
+        for data_count in range(poll_count, 10):
+            CGroupsTelemetry.poll_all_tracked()
+            self.assertEqual(0, patch_periodic_warn.call_count)
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch("azurelinuxagent.common.logger.periodic_warn")
-    def test_telemetry_polling_to_generate_transient_logs_ioerror_permission_denied(self, patch_periodic_warn):
+    @patch("azurelinuxagent.common.utils.fileutil.read_file")
+    def test_telemetry_polling_to_generate_transient_logs_ioerror_permission_denied(self, mock_read_file,
+                                                                                    patch_periodic_warn, *args):
         num_extensions = 1
         num_controllers = 2
         is_active_check_per_controller = 2
@@ -316,18 +309,22 @@ class TestCGroupsTelemetry(AgentTestCase):
         # Expecting logs to be present for different kind of errors
         io_error_3 = IOError()
         io_error_3.errno = errno.EPERM
+        mock_read_file.side_effect = io_error_3
 
-        with patch("azurelinuxagent.common.utils.fileutil.read_file", side_effect=io_error_3):
-            poll_count = 1
-            expected_count_per_call = num_controllers + is_active_check_per_controller
-            # each collect per controller would generate a log statement, and each cgroup would invoke a
-            # is active check raising an exception
+        poll_count = 1
+        expected_count_per_call = num_controllers + is_active_check_per_controller
+        # each collect per controller would generate a log statement, and each cgroup would invoke a
+        # is active check raising an exception
 
-            for data_count in range(poll_count, 10):
-                CGroupsTelemetry.poll_all_tracked()
-                self.assertEqual(poll_count * expected_count_per_call, patch_periodic_warn.call_count)
+        for data_count in range(poll_count, 10):
+            CGroupsTelemetry.poll_all_tracked()
+            self.assertEqual(poll_count * expected_count_per_call, patch_periodic_warn.call_count)
 
-    def test_telemetry_polling_to_generate_transient_logs_index_error(self):
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
+    @patch("azurelinuxagent.common.utils.fileutil.read_file")
+    def test_telemetry_polling_to_generate_transient_logs_index_error(self, mock_read_file, *args):
         num_extensions = 1
         for i in range(num_extensions):
             dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
@@ -339,13 +336,17 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         # Generating a different kind of error (non-IOError) to check the logging.
         # Trying to invoke IndexError during the getParameter call
-        with patch("azurelinuxagent.common.utils.fileutil.read_file", return_value=''):
-            with patch("azurelinuxagent.common.logger.periodic_warn") as patch_periodic_warn:
-                expected_call_count = 2  # 1 periodic warning for the cpu cgroups, and 1 for memory
-                for data_count in range(1, 10):
-                    CGroupsTelemetry.poll_all_tracked()
-                    self.assertEqual(expected_call_count, patch_periodic_warn.call_count)
+        mock_read_file.return_value = ''
+
+        with patch("azurelinuxagent.common.logger.periodic_warn") as patch_periodic_warn:
+            expected_call_count = 1  # called only once at start, and then gets removed from the tracked data.
+            for data_count in range(1, 10):
+                CGroupsTelemetry.poll_all_tracked()
+                self.assertEqual(expected_call_count, patch_periodic_warn.call_count)
 
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._update_cpu_data")
     def test_telemetry_calculations(self, *args):
         num_polls = 10
         num_extensions = 1
@@ -369,11 +370,11 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage") as patch_get_memory_max_usage:
             with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage") as patch_get_memory_usage:
-                with patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage") as patch_get_cpu_usage:
+                with patch("azurelinuxagent.common.cgroup.CpuCgroup._get_cpu_percent") as patch_get_cpu_percent:
                     with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
                         for i in range(num_polls):
                             patch_is_active.return_value = True
-                            patch_get_cpu_usage.return_value = cpu_percent_values[i]
+                            patch_get_cpu_percent.return_value = cpu_percent_values[i]
                             patch_get_memory_usage.return_value = memory_usage_values[i]  # example 200 MB
                             patch_get_memory_max_usage.return_value = max_memory_usage_values[i]  # example 450 MB
                             metrics = CGroupsTelemetry.poll_all_tracked()
@@ -403,25 +404,29 @@ class TestCGroupsTelemetry(AgentTestCase):
             self.assertListEqual(generate_metric_list(cpu_percent_values),
                                  collected_metrics[name]["cpu"]["cur_cpu"][0:5])
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cgroup_tracking(self, *args):
-        with patch("azurelinuxagent.common.cgroup.CpuCgroup.initialize_cpu_usage") as patch_initialize_cpu_usage:
-            num_extensions = 5
-            num_controllers = 2
-            for i in range(num_extensions):
-                dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
-                CGroupsTelemetry.track_cgroup(dummy_cpu_cgroup)
+        num_extensions = 5
+        num_controllers = 2
+        for i in range(num_extensions):
+            dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
+            CGroupsTelemetry.track_cgroup(dummy_cpu_cgroup)
 
-                dummy_memory_cgroup = CGroup.create("dummy_memory_path_{0}".format(i), "memory",
-                                                    "dummy_extension_{0}".format(i))
-                CGroupsTelemetry.track_cgroup(dummy_memory_cgroup)
+            dummy_memory_cgroup = CGroup.create("dummy_memory_path_{0}".format(i), "memory",
+                                                "dummy_extension_{0}".format(i))
+            CGroupsTelemetry.track_cgroup(dummy_memory_cgroup)
 
-            for i in range(num_extensions):
-                self.assertTrue(CGroupsTelemetry.is_tracked("dummy_cpu_path_{0}".format(i)))
-                self.assertTrue(CGroupsTelemetry.is_tracked("dummy_memory_path_{0}".format(i)))
+        for i in range(num_extensions):
+            self.assertTrue(CGroupsTelemetry.is_tracked("dummy_cpu_path_{0}".format(i)))
+            self.assertTrue(CGroupsTelemetry.is_tracked("dummy_memory_path_{0}".format(i)))
 
-            self.assertEqual(num_extensions * num_controllers, len(CGroupsTelemetry._tracked))
-            self.assertEqual(num_extensions, patch_initialize_cpu_usage.call_count)
+        self.assertEqual(num_extensions * num_controllers, len(CGroupsTelemetry._tracked))
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cgroup_pruning(self, *args):
         num_extensions = 5
         num_controllers = 2
@@ -447,6 +452,9 @@ class TestCGroupsTelemetry(AgentTestCase):
 
         self.assertEqual(0, len(CGroupsTelemetry._tracked))
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_cgroup_is_tracked(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
@@ -464,6 +472,9 @@ class TestCGroupsTelemetry(AgentTestCase):
         self.assertFalse(CGroupsTelemetry.is_tracked("not_present_cpu_dummy_path"))
         self.assertFalse(CGroupsTelemetry.is_tracked("not_present_memory_dummy_path"))
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_process_cgroup_metric_with_incorrect_cgroups_mounted(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
@@ -490,6 +501,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                     collected_metrics[name] = CGroupsTelemetry._process_cgroup_metric(cgroup_metrics)
                     self.assertEqual(collected_metrics[name], {})  # empty
 
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_process_cgroup_metric_with_no_memory_cgroup_mounted(self, *args):
         num_extensions = 5
 
@@ -501,14 +514,14 @@ class TestCGroupsTelemetry(AgentTestCase):
                                                 "dummy_extension_{0}".format(i))
             CGroupsTelemetry.track_cgroup(dummy_memory_cgroup)
 
-        with patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage") as patch_get_cpu_usage:
+        with patch("azurelinuxagent.common.cgroup.CpuCgroup._get_cpu_percent") as patch_get_cpu_percent:
             with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage") as patch_get_memory_usage:
                 with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
                     patch_is_active.return_value = True
                     patch_get_memory_usage.side_effect = Exception("File not found")
 
                     current_cpu = 30
-                    patch_get_cpu_usage.return_value = current_cpu
+                    patch_get_cpu_percent.return_value = current_cpu
 
                     poll_count = 1
 
@@ -525,6 +538,8 @@ class TestCGroupsTelemetry(AgentTestCase):
                     self.assertEqual(CGroupsTelemetry._cgroup_metrics.__len__(), num_extensions)
                     self._assert_cgroup_metrics_equal([], [], [])
 
+    @patch("azurelinuxagent.common.cgroup.CpuCgroup._get_current_cpu_total")
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_process_cgroup_metric_with_no_cpu_cgroup_mounted(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
@@ -570,6 +585,7 @@ class TestCGroupsTelemetry(AgentTestCase):
     @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage", side_effect=raise_ioerror)
     @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage", side_effect=raise_ioerror)
     @patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage", side_effect=raise_ioerror)
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil.get_total_cpu_ticks_since_boot")
     def test_extension_telemetry_not_sent_for_empty_perf_metrics(self, *args):
         num_extensions = 5
         for i in range(num_extensions):
diff --git a/tests/daemon/test_resourcedisk.py b/tests/daemon/test_resourcedisk.py
index ebaa18c9..3f43c733 100644
--- a/tests/daemon/test_resourcedisk.py
+++ b/tests/daemon/test_resourcedisk.py
@@ -26,7 +26,7 @@ class TestResourceDisk(AgentTestCase):
         partition = '/dev/sdb1'
         mountpoint = '/mnt/resource'
         options = None
-        expected = 'mount -t ext3 /dev/sdb1 /mnt/resource'
+        expected = 'mount /dev/sdb1 /mnt/resource'
         rdh = ResourceDiskHandler()
         mount_string = rdh.get_mount_string(options, partition, mountpoint)
         self.assertEqual(expected, mount_string)
@@ -35,7 +35,7 @@ class TestResourceDisk(AgentTestCase):
         partition = '/dev/sdb1'
         mountpoint = '/mnt/resource'
         options = 'noexec,noguid,nodev'
-        expected = 'mount -t ext3 -o noexec,noguid,nodev /dev/sdb1 /mnt/resource'
+        expected = 'mount -o noexec,noguid,nodev /dev/sdb1 /mnt/resource'
         rdh = ResourceDiskHandler()
         mount_string = rdh.get_mount_string(options, partition, mountpoint)
         self.assertEqual(expected, mount_string)
diff --git a/tests/data/cgroups/cpuacct.stat_t0 b/tests/data/cgroups/cpuacct.stat_t0
deleted file mode 100644
index fd0576fd..00000000
--- a/tests/data/cgroups/cpuacct.stat_t0
+++ /dev/null
@@ -1,2 +0,0 @@
-user 42380
-system 21383
diff --git a/tests/data/cgroups/cpuacct.stat_t1 b/tests/data/cgroups/cpuacct.stat_t1
deleted file mode 100644
index 3c0def97..00000000
--- a/tests/data/cgroups/cpuacct.stat_t1
+++ /dev/null
@@ -1,2 +0,0 @@
-user 42390
-system 21390
diff --git a/tests/data/cgroups/cpuacct.stat_t2 b/tests/data/cgroups/cpuacct.stat_t2
deleted file mode 100644
index c79bfeb9..00000000
--- a/tests/data/cgroups/cpuacct.stat_t2
+++ /dev/null
@@ -1,2 +0,0 @@
-user 42417
-system 21428
diff --git a/tests/data/cgroups/proc_stat_t1 b/tests/data/cgroups/dummy_proc_stat
similarity index 53%
rename from tests/data/cgroups/proc_stat_t1
rename to tests/data/cgroups/dummy_proc_stat
index 59e41c00..37288001 100644
--- a/tests/data/cgroups/proc_stat_t1
+++ b/tests/data/cgroups/dummy_proc_stat
@@ -1,12 +1,12 @@
-cpu  1251670 18548 368052 3877822 7926 0 28103 0 0 0
-cpu0 307860 4380 135060 2583922 5171 0 11173 0 0 0
-cpu1 318474 4742 81276 428425 1019 0 8384 0 0 0
-cpu2 313521 4916 76464 431225 748 0 4297 0 0 0
-cpu3 311814 4508 75250 434248 986 0 4247 0 0 0
-intr 81910494 14 5118 0 0 0 0 0 0 1 18573886 0 0 977671 0 0 0 0 0 0 0 1291486 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25913782 290 40 7152 56 9383 8954 8604958 0 0 0 0 0 0 0 0 0 0 0 0 10367 107667 2672 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-ctxt 150920611
-btime 1575311513
-processes 49693
-procs_running 4
+cpu  40362 2657 5493 349635 341 0 938 0 0 0
+cpu0 10043 1084 1319 86971 129 0 369 0 0 0
+cpu1 10069 653 1244 87708 51 0 202 0 0 0
+cpu2 10416 528 1492 87075 86 0 239 0 0 0
+cpu3 9833 391 1436 87878 73 0 126 0 0 0
+intr 1202440 15 1020 0 0 0 0 0 0 1 579 0 0 85138 0 0 0 0 0 0 0 0 0 0 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 572 65513 499 34 53368 177617 392 149 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ctxt 2294069
+btime 1562092648
+processes 3715
+procs_running 1
 procs_blocked 0
-softirq 37131388 11544829 8149486 5023 1127332 54 54 1776947 7667169 0 6860494
+softirq 1244004 191505 366613 7 1187 62878 0 1006 328256 2205 290347
\ No newline at end of file
diff --git a/tests/data/cgroups/proc_stat_t2 b/tests/data/cgroups/dummy_proc_stat_updated
similarity index 53%
rename from tests/data/cgroups/proc_stat_t2
rename to tests/data/cgroups/dummy_proc_stat_updated
index 63ecce02..f0ef0c91 100644
--- a/tests/data/cgroups/proc_stat_t2
+++ b/tests/data/cgroups/dummy_proc_stat_updated
@@ -1,12 +1,12 @@
-cpu  1293131 18554 388040 3961230 8246 0 28928 0 0 0
-cpu0 317730 4381 146935 2591197 5184 0 11535 0 0 0
-cpu1 329039 4746 84213 453402 1178 0 8587 0 0 0
-cpu2 324213 4917 79154 456426 826 0 4410 0 0 0
-cpu3 322147 4509 77737 460203 1057 0 4395 0 0 0
-intr 89815534 14 5118 0 0 0 0 0 0 1 21544211 0 0 977671 0 0 0 0 0 0 0 1306547 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29282036 290 40 7566 56 10241 9584 8929545 0 0 0 0 0 0 0 0 0 0 0 0 11076 107667 2867 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-ctxt 162816290
-btime 1575311513
-processes 49900
+cpu  286534 2705 70195 2971012 1358 0 11637 0 0 0
+cpu0 73053 1096 18020 739721 460 0 3510 0 0 0
+cpu1 70934 664 16722 745032 184 0 2552 0 0 0
+cpu2 74991 539 17715 739096 505 0 3128 0 0 0
+cpu3 67554 405 17736 747162 208 0 2446 0 0 0
+intr 16171532 15 6790 0 0 0 0 0 0 1 2254 0 0 550798 0 0 0 0 0 0 0 0 0 0 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50645 129322 4209 34 458202 1721987 504 149 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ctxt 36112837
+btime 1562092648
+processes 27949
 procs_running 2
-procs_blocked 0
-softirq 38518020 11917848 8439326 5100 1170153 54 54 1834614 7944771 0 7206100
+procs_blocked 1
+softirq 17121870 1838273 5563635 21 8079 119728 0 6931 5982692 2629 3599882
\ No newline at end of file
diff --git a/tests/data/cgroups/proc_stat_t0 b/tests/data/cgroups/proc_stat_t0
deleted file mode 100644
index 5f5ebda6..00000000
--- a/tests/data/cgroups/proc_stat_t0
+++ /dev/null
@@ -1,12 +0,0 @@
-cpu  1242996 18547 360544 3839094 7843 0 27848 0 0 0
-cpu0 305718 4380 129988 2580650 5164 0 11050 0 0 0
-cpu1 316342 4742 80358 416652 1001 0 8333 0 0 0
-cpu2 311233 4916 75691 419501 720 0 4268 0 0 0
-cpu3 309702 4508 74507 422289 956 0 4196 0 0 0
-intr 78869641 14 5118 0 0 0 0 0 0 1 17275956 0 0 977671 0 0 0 0 0 0 0 1285764 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24614913 290 40 7069 56 9208 8660 8574436 0 0 0 0 0 0 0 0 0 0 0 0 10238 107667 2597 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-ctxt 145952189
-btime 1575311513
-processes 49655
-procs_running 2
-procs_blocked 0
-softirq 36699327 11497379 8043346 4993 1111315 54 54 1755674 7556345 0 6730167
diff --git a/tests/ga/test_extension.py b/tests/ga/test_extension.py
index 1868f52b..ff32defc 100644
--- a/tests/ga/test_extension.py
+++ b/tests/ga/test_extension.py
@@ -16,6 +16,7 @@
 #
 
 import os.path
+import subprocess
 import unittest
 
 from datetime import timedelta
@@ -1464,24 +1465,68 @@ class TestExtension(ExtensionTestCase):
         self._assert_no_handler_status(protocol.report_vm_status)
 
     @patch('azurelinuxagent.ga.exthandlers.HandlerManifest.get_update_command')
-    def test_upgrade_failure(self, patch_get_update_command, *args):
+    def test_extension_upgrade_failure_when_new_version_update_fails(self, patch_get_update_command, *args):
         """
-        Extension upgrade failure should not be retried
+        When the update command of the new extension fails, it should result in the new extension failed and the
+        old extension disabled. On the next goal state, the entire upgrade scenario should be retried (once),
+        meaning the download, initialize and update are called on the new extension.
+        Note: we don't re-download the zip since it wasn't cleaned up in the previous goal state (we only clean up
+        NotInstalled handlers), so we just re-use the existing zip of the new extension.
         """
         test_data, exthandlers_handler, protocol = self._set_up_update_test_and_update_gs(patch_get_update_command,
                                                                                           *args)
+        extension_name = exthandlers_handler.ext_handlers.extHandlers[0].name
+        extension_calls = []
+        original_popen = subprocess.Popen
 
-        exthandlers_handler.run()
-        self.assertEqual(1, patch_get_update_command.call_count)
+        def mock_popen(*args, **kwargs):
+            # Maintain an internal list of invoked commands of the test extension to assert on later
+            if extension_name in args[0]:
+                extension_calls.append(args[0])
+            return original_popen(*args, **kwargs)
 
-        # On the next iteration, update should not be retried
-        exthandlers_handler.run()
-        self.assertEqual(1, patch_get_update_command.call_count)
+        with patch('azurelinuxagent.common.cgroupapi.subprocess.Popen', side_effect=mock_popen):
+            exthandlers_handler.run()
+            update_command_count = len([extension_call for extension_call in extension_calls
+                                        if patch_get_update_command.return_value in extension_call])
+            enable_command_count = len([extension_call for extension_call in extension_calls
+                                        if "-enable" in extension_call])
+            
+            self.assertEquals(1, update_command_count)
+            self.assertEquals(0, enable_command_count)
 
-        self._assert_handler_status(protocol.report_vm_status, "NotReady", expected_ext_count=1, version="1.0.1")
+            # We report the failure of the new extension version
+            self._assert_handler_status(protocol.report_vm_status, "NotReady", expected_ext_count=1, version="1.0.1")
+
+            # Ensure we are processing the same goal state only once
+            loop_run = 5
+            for x in range(loop_run):
+                exthandlers_handler.run()
+
+            update_command_count = len([extension_call for extension_call in extension_calls
+                                        if patch_get_update_command.return_value in extension_call])
+            enable_command_count = len([extension_call for extension_call in extension_calls
+                                        if "-enable" in extension_call])
+            self.assertEquals(1, update_command_count)
+            self.assertEquals(0, enable_command_count)
+
+            # If the incarnation number changes (there's a new goal state), ensure we go through the entire upgrade
+            # process again.
+            test_data.goal_state = test_data.goal_state.replace("<Incarnation>2<", "<Incarnation>3<")
+            exthandlers_handler.run()
+
+            update_command_count = len([extension_call for extension_call in extension_calls
+                                        if patch_get_update_command.return_value in extension_call])
+            enable_command_count = len([extension_call for extension_call in extension_calls
+                                        if "-enable" in extension_call])
+            self.assertEquals(2, update_command_count)
+            self.assertEquals(0, enable_command_count)
+
+            # We report the failure of the new extension version
+            self._assert_handler_status(protocol.report_vm_status, "NotReady", expected_ext_count=1, version="1.0.1")
 
     @patch('azurelinuxagent.ga.exthandlers.HandlerManifest.get_disable_command')
-    def test__extension_upgrade_failure_when_prev_version_disable_fails(self, patch_get_disable_command, *args):
+    def test_extension_upgrade_failure_when_prev_version_disable_fails(self, patch_get_disable_command, *args):
         test_data, exthandlers_handler, protocol = self._set_up_update_test_and_update_gs(patch_get_disable_command,
                                                                                           *args)
 
@@ -1503,7 +1548,7 @@ class TestExtension(ExtensionTestCase):
             self.assertEqual(0, patch_get_enable_command.call_count)
 
     @patch('azurelinuxagent.ga.exthandlers.HandlerManifest.get_disable_command')
-    def test__extension_upgrade_failure_when_prev_version_disable_fails_and_recovers_on_next_incarnation(self, patch_get_disable_command,
+    def test_extension_upgrade_failure_when_prev_version_disable_fails_and_recovers_on_next_incarnation(self, patch_get_disable_command,
                                                                                                          *args):
         test_data, exthandlers_handler, protocol = self._set_up_update_test_and_update_gs(patch_get_disable_command,
                                                                                           *args)
@@ -1536,7 +1581,7 @@ class TestExtension(ExtensionTestCase):
                 self._assert_handler_status(protocol.report_vm_status, "Ready", expected_ext_count=1, version="1.0.1")
 
     @patch('azurelinuxagent.ga.exthandlers.HandlerManifest.get_disable_command')
-    def test__extension_upgrade_failure_when_prev_version_disable_fails_incorrect_zip(self, patch_get_disable_command,
+    def test_extension_upgrade_failure_when_prev_version_disable_fails_incorrect_zip(self, patch_get_disable_command,
                                                                                       *args):
         test_data, exthandlers_handler, protocol = self._set_up_update_test_and_update_gs(patch_get_disable_command,
                                                                                           *args)
@@ -1564,7 +1609,7 @@ class TestExtension(ExtensionTestCase):
                     self.assertEqual(0, patch_get_enable_command.call_count)
 
     @patch('azurelinuxagent.ga.exthandlers.HandlerManifest.get_disable_command')
-    def test__old_handler_reports_failure_on_disable_fail_on_update(self, patch_get_disable_command, *args):
+    def test_old_handler_reports_failure_on_disable_fail_on_update(self, patch_get_disable_command, *args):
         old_version, new_version = "1.0.0", "1.0.1"
         test_data, exthandlers_handler, protocol = self._set_up_update_test_and_update_gs(patch_get_disable_command,
                                                                                           *args)
diff --git a/tests/ga/test_monitor.py b/tests/ga/test_monitor.py
index 8b3a2144..33bd5208 100644
--- a/tests/ga/test_monitor.py
+++ b/tests/ga/test_monitor.py
@@ -30,7 +30,7 @@ from nose.plugins.attrib import attr
 
 import azurelinuxagent.common.conf as conf
 from azurelinuxagent.common import event, logger
-from azurelinuxagent.common.cgroup import CGroup, CpuCgroup, MemoryCgroup
+from azurelinuxagent.common.cgroup import CGroup, CpuCgroup
 from azurelinuxagent.common.cgroupconfigurator import CGroupConfigurator
 from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry, MetricValue
 from azurelinuxagent.common.datacontract import get_properties
@@ -901,6 +901,9 @@ class TestExtensionMetricsDataTelemetry(AgentTestCase):
         self.assertEqual(0, patch_add_metric.call_count)
         monitor_handler.stop()
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch('azurelinuxagent.common.event.EventLogger.add_metric')
     @patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage")
     @patch('azurelinuxagent.common.logger.Logger.periodic_warn')
@@ -911,7 +914,7 @@ class TestExtensionMetricsDataTelemetry(AgentTestCase):
         ioerror.errno = 2
         patch_get_memory_usage.side_effect = ioerror
 
-        CGroupsTelemetry._tracked.append(MemoryCgroup("cgroup_name", "/test/path"))
+        CGroupsTelemetry._tracked.append(CpuCgroup("cgroup_name", "/test/path"))
 
         monitor_handler = get_monitor_handler()
         monitor_handler.init_protocols()
@@ -922,6 +925,9 @@ class TestExtensionMetricsDataTelemetry(AgentTestCase):
         self.assertEqual(0, patch_add_metric.call_count)  # No metrics should be sent.
         monitor_handler.stop()
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     @patch('azurelinuxagent.common.event.EventLogger.add_metric')
     @patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage")
     @patch('azurelinuxagent.common.logger.Logger.periodic_warn')
@@ -1135,6 +1141,9 @@ for i in range(3):
 
         monitor_handler.stop()
 
+    # mocking get_proc_stat to make it run on Mac and other systems. This test does not need to read the values of the
+    # /proc/stat file on the filesystem.
+    @patch("azurelinuxagent.common.osutil.default.DefaultOSUtil._get_proc_stat")
     def test_generate_extension_metrics_telemetry_dictionary(self, *args):
         num_polls = 10
         num_extensions = 1
@@ -1146,28 +1155,27 @@ for i in range(3):
         memory_usage_values = [random.randint(0, 8 * 1024 ** 3) for _ in range(num_polls)]
         max_memory_usage_values = [random.randint(0, 8 * 1024 ** 3) for _ in range(num_polls)]
 
-        # no need to initialize the CPU usage, since we mock get_cpu_usage() below
-        with patch("azurelinuxagent.common.cgroup.CpuCgroup.initialize_cpu_usage"):
-            for i in range(num_extensions):
-                dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
-                CGroupsTelemetry.track_cgroup(dummy_cpu_cgroup)
+        for i in range(num_extensions):
+            dummy_cpu_cgroup = CGroup.create("dummy_cpu_path_{0}".format(i), "cpu", "dummy_extension_{0}".format(i))
+            CGroupsTelemetry.track_cgroup(dummy_cpu_cgroup)
 
-                dummy_memory_cgroup = CGroup.create("dummy_memory_path_{0}".format(i), "memory",
-                                                    "dummy_extension_{0}".format(i))
-                CGroupsTelemetry.track_cgroup(dummy_memory_cgroup)
+            dummy_memory_cgroup = CGroup.create("dummy_memory_path_{0}".format(i), "memory",
+                                                "dummy_extension_{0}".format(i))
+            CGroupsTelemetry.track_cgroup(dummy_memory_cgroup)
 
         self.assertEqual(2 * num_extensions, len(CGroupsTelemetry._tracked))
 
         with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_max_memory_usage") as patch_get_memory_max_usage:
             with patch("azurelinuxagent.common.cgroup.MemoryCgroup.get_memory_usage") as patch_get_memory_usage:
-                with patch("azurelinuxagent.common.cgroup.CpuCgroup.get_cpu_usage") as patch_get_cpu_usage:
-                    with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
-                        for i in range(num_polls):
-                            patch_is_active.return_value = True
-                            patch_get_cpu_usage.return_value = cpu_percent_values[i]
-                            patch_get_memory_usage.return_value = memory_usage_values[i]  # example 200 MB
-                            patch_get_memory_max_usage.return_value = max_memory_usage_values[i]  # example 450 MB
-                            CGroupsTelemetry.poll_all_tracked()
+                with patch("azurelinuxagent.common.cgroup.CpuCgroup._get_cpu_percent") as patch_get_cpu_percent:
+                    with patch("azurelinuxagent.common.cgroup.CpuCgroup._update_cpu_data") as patch_update_cpu_data:
+                        with patch("azurelinuxagent.common.cgroup.CGroup.is_active") as patch_is_active:
+                            for i in range(num_polls):
+                                patch_is_active.return_value = True
+                                patch_get_cpu_percent.return_value = cpu_percent_values[i]
+                                patch_get_memory_usage.return_value = memory_usage_values[i]  # example 200 MB
+                                patch_get_memory_max_usage.return_value = max_memory_usage_values[i]  # example 450 MB
+                                CGroupsTelemetry.poll_all_tracked()
 
         performance_metrics = CGroupsTelemetry.report_all_tracked()