Repository: Azure/WALinuxAgent
Pull request #1707 (2019-11-10 00:22:03)

Refactor adding the common fields to single method
<!-- DO NOT DELETE THIS TEMPLATE -->

## Description
To bring the logic of adding all the common fields into one method.

Issue # <!-- if any -->
<!--
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
- [x] The title of the PR is clear and informative.
- [x] 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).
- [x] Except for special cases involving multiple contributors, the PR is started from a fork of the main repository, not a branch.
- [x] If applicable, the PR references the bug/issue that it fixes in the description.
- [x] New Unit tests were added for the changes made and Travis.CI is passing.

### Quality of Code and Contribution Guidelines
- [x] 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/1707)
<!-- Reviewable:end -->


codecov[bot]: # [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`develop@7d1920d`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `90.9%`.

[![Impacted file tree graph](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707/graphs/tree.svg?width=650&token=ae90E2KYCw&height=150&src=pr)](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             develop    #1707   +/-   ##
==========================================
  Coverage           ?   67.68%           
==========================================
  Files              ?       80           
  Lines              ?    11522           
  Branches           ?     1617           
==========================================
  Hits               ?     7799           
  Misses             ?     3381           
  Partials           ?      342
```


| [Impacted Files](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [azurelinuxagent/common/telemetryevent.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi90ZWxlbWV0cnlldmVudC5weQ==) | `100% <ø> (ø)` | |
| [azurelinuxagent/ga/monitor.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2dhL21vbml0b3IucHk=) | `88.19% <100%> (ø)` | |
| [azurelinuxagent/common/event.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9ldmVudC5weQ==) | `84.72% <100%> (ø)` | |
| [azurelinuxagent/common/future.py](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707/diff?src=pr&el=tree#diff-YXp1cmVsaW51eGFnZW50L2NvbW1vbi9mdXR1cmUucHk=) | `42.1% <60%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707?src=pr&el=footer). Last update [7d1920d...8e298d3](https://codecov.io/gh/Azure/WALinuxAgent/pull/1707?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/azurelinuxagent/common/event.py b/azurelinuxagent/common/event.py
index 415332fe..a9df545f 100644
--- a/azurelinuxagent/common/event.py
+++ b/azurelinuxagent/common/event.py
@@ -22,13 +22,14 @@ import sys
 import threading
 import time
 import traceback
+from collections import namedtuple
 from datetime import datetime
 
 import azurelinuxagent.common.conf as conf
 import azurelinuxagent.common.logger as logger
 from azurelinuxagent.common.exception import EventError
-from azurelinuxagent.common.future import ustr
-from azurelinuxagent.common.datacontract import get_properties
+from azurelinuxagent.common.future import ustr, OrderedDict
+from azurelinuxagent.common.datacontract import get_properties, DataContractList
 from azurelinuxagent.common.telemetryevent import TelemetryEventParam, TelemetryEvent
 from azurelinuxagent.common.utils import fileutil, textutil
 from azurelinuxagent.common.version import CURRENT_VERSION, CURRENT_AGENT
@@ -281,7 +282,7 @@ class EventLogger(object):
         event.parameters.append(TelemetryEventParam('Duration', int(duration)))
         event.parameters.append(TelemetryEventParam('ExtensionType', str(evt_type)))
 
-        self.add_default_parameters_to_event(event)
+        event.parameters = self.add_default_parameters_to_event(event.parameters)
         data = get_properties(event)
         try:
             self.save_event(json.dumps(data))
@@ -308,7 +309,7 @@ class EventLogger(object):
         event.parameters.append(TelemetryEventParam('Context2', ''))
         event.parameters.append(TelemetryEventParam('Context3', ''))
 
-        self.add_default_parameters_to_event(event)
+        event.parameters = self.add_default_parameters_to_event(event.parameters)
         data = get_properties(event)
         try:
             self.save_event(json.dumps(data))
@@ -336,7 +337,7 @@ class EventLogger(object):
         event.parameters.append(TelemetryEventParam('Instance', str(instance)))
         event.parameters.append(TelemetryEventParam('Value', float(value)))
 
-        self.add_default_parameters_to_event(event)
+        event.parameters = self.add_default_parameters_to_event(event.parameters)
         data = get_properties(event)
         try:
             self.save_event(json.dumps(data))
@@ -344,26 +345,51 @@ class EventLogger(object):
             logger.error("{0}", e)
 
     @staticmethod
-    def add_default_parameters_to_event(event, set_default_values=False):
-        # We write the GAVersion here rather than add it in azurelinuxagent.ga.monitor.MonitorHandler.add_sysinfo
-        # as there could be a possibility of events being sent with newer version of the agent, rather than the agent
-        # version generating the event.
+    def add_default_parameters_to_event(event_parameters, set_values_for_agent=True):
+        """
+        Default fields are only populated by Agent and not the extension. Agent will fill up any event if they don't
+        have the default params. Example: GAVersion and ContainerId are populated for agent events on the fly,
+        but not for extension events. Add it if it's missing.
+
+        We write the GAVersion here rather than add it in azurelinuxagent.ga.monitor.MonitorHandler.add_sysinfo
+        as there could be a possibility of events being sent with newer version of the agent, rather than the agent
+        version generating the event.
         # Old behavior example: V1 writes the event on the disk and finds an update immediately, and updates. Now the
-        # new monitor thread would pick up the events from the disk and send it with the CURRENT_AGENT, which would have
-        # newer version of the agent. This causes confusion.
-        #
-        # ContainerId can change due to live migration and we want to preserve the container Id of the container writing
-        # the event, rather than sending the event.
-        # OpcodeName: This is used as the actual time of event generation.
+        new monitor thread would pick up the events from the disk and send it with the CURRENT_AGENT, which would have
+        newer version of the agent. This causes confusion.
 
-        default_parameters = [("GAVersion", CURRENT_AGENT), ('ContainerId', get_container_id_from_env()),
-                              ('OpcodeName', datetime.utcnow().__str__()),
-                              ('EventTid', threading.current_thread().ident),
-                              ('EventPid', os.getpid()), ("TaskName", threading.current_thread().getName()),
-                              ("KeywordName", '')]
+        ContainerId can change due to live migration and we want to preserve the container Id of the container writing
+        the event, rather than sending the event.
+        OpcodeName - This is used as the actual time of event generation.
+
+        :param event_parameters: List of parameters of the event.
+        :param set_values_for_agent: Need default values populated or not. Extensions need only GAVersion and
+                                            ContainerId to be populated and others should be
+        :return: Event with default parameters populated (either values for agent or extension)
+        """
+        DefaultParameter = namedtuple('DefaultParameter', ['name', 'value'])
+        default_parameters = [DefaultParameter("GAVersion", CURRENT_AGENT),
+                              DefaultParameter('ContainerId', get_container_id_from_env()),
+                              DefaultParameter('OpcodeName', datetime.utcnow().__str__() if set_values_for_agent else ""),
+                              DefaultParameter('EventTid', threading.current_thread().ident if set_values_for_agent else 0),
+                              DefaultParameter('EventPid', os.getpid() if set_values_for_agent else 0),
+                              DefaultParameter("TaskName", threading.current_thread().getName() if set_values_for_agent else ""),
+                              DefaultParameter("KeywordName", '')]
+
+        # Converting the event_parameters into a dictionary as it helps to easily look up and get values
+        param_names = OrderedDict([(param.name, param.value) for param in event_parameters])
 
         for param in default_parameters:
-            event.parameters.append(TelemetryEventParam(param[0], param[1]))
+            if param.name not in param_names or set_values_for_agent:
+                # If set_values_for_agent, we disregard any values already set for an existing default property and
+                # replaces it with a latest entry.
+                param_names[param.name] = param.value
+
+        parameters = DataContractList(TelemetryEventParam)
+        for name, value in param_names.items():
+            parameters.append(TelemetryEventParam(name, value))
+
+        return parameters
 
 
 __event_logger__ = EventLogger()
diff --git a/azurelinuxagent/common/future.py b/azurelinuxagent/common/future.py
index f546bc15..3f2fa8c3 100644
--- a/azurelinuxagent/common/future.py
+++ b/azurelinuxagent/common/future.py
@@ -23,6 +23,8 @@ if sys.version_info[0] == 3:
 
     bytebuffer = memoryview
 
+    from collections import OrderedDict
+
 elif sys.version_info[0] == 2:
     import httplib as httpclient
     from urlparse import urlparse
@@ -32,6 +34,10 @@ elif sys.version_info[0] == 2:
 
     bytebuffer = buffer
 
+    if sys.version_info[1] >= 7:
+        from collections import OrderedDict  # For Py 2.7+
+    else:
+        from ordereddict import OrderedDict  # Works only on 2.6
 else:
     raise ImportError("Unknown python version: {0}".format(sys.version_info))
 
diff --git a/azurelinuxagent/common/telemetryevent.py b/azurelinuxagent/common/telemetryevent.py
index 8c3eb71b..79fa504c 100644
--- a/azurelinuxagent/common/telemetryevent.py
+++ b/azurelinuxagent/common/telemetryevent.py
@@ -28,7 +28,6 @@ class TelemetryEventParam(DataContract):
     def __eq__(self, other):
         return isinstance(other, TelemetryEventParam) and other.name == self.name and other.value == self.value
 
-
 class TelemetryEvent(DataContract):
     def __init__(self, eventId=None, providerId=None):
         self.eventId = eventId
diff --git a/azurelinuxagent/ga/monitor.py b/azurelinuxagent/ga/monitor.py
index 42511dba..cd4b3d02 100644
--- a/azurelinuxagent/ga/monitor.py
+++ b/azurelinuxagent/ga/monitor.py
@@ -26,11 +26,10 @@ import uuid
 import azurelinuxagent.common.conf as conf
 import azurelinuxagent.common.logger as logger
 import azurelinuxagent.common.utils.networkutil as networkutil
-
 from azurelinuxagent.common.cgroupstelemetry import CGroupsTelemetry
+from azurelinuxagent.common.datacontract import set_properties
 from azurelinuxagent.common.errorstate import ErrorState
-from azurelinuxagent.common.event import add_event, WALAEventOperation, CONTAINER_ID_ENV_VARIABLE, \
-    get_container_id_from_env
+from azurelinuxagent.common.event import EventLogger
 from azurelinuxagent.common.event import add_event, WALAEventOperation, report_metric
 from azurelinuxagent.common.exception import EventError, ProtocolError, OSUtilError, HttpError
 from azurelinuxagent.common.future import ustr
@@ -39,11 +38,10 @@ from azurelinuxagent.common.protocol import get_protocol_util
 from azurelinuxagent.common.protocol.healthservice import HealthService
 from azurelinuxagent.common.protocol.imds import get_imds_client
 from azurelinuxagent.common.telemetryevent import TelemetryEvent, TelemetryEventParam, TelemetryEventList
-from azurelinuxagent.common.datacontract import set_properties
 from azurelinuxagent.common.utils.restutil import IOErrorCounter
 from azurelinuxagent.common.utils.textutil import parse_doc, findall, find, getattrib, hash_strings
 from azurelinuxagent.common.version import DISTRO_NAME, DISTRO_VERSION, \
-    DISTRO_CODE_NAME, AGENT_NAME, CURRENT_AGENT, CURRENT_VERSION, AGENT_EXECUTION_MODE
+    DISTRO_CODE_NAME, AGENT_NAME, CURRENT_VERSION, AGENT_EXECUTION_MODE
 
 
 def parse_event(data_str):
@@ -321,14 +319,6 @@ class MonitorHandler(object):
         sysinfo_names = [v.name for v in self.sysinfo]
         final_parameters = []
 
-        # Refer: azurelinuxagent.common.event.EventLogger.add_default_parameters_to_event for agent specific values.
-        #
-        # Default fields are only populated by Agent and not the extension. Agent will fill up any event if they don't
-        # have the default params. Example: GAVersion and ContainerId are populated for agent events on the fly,
-        # but not for extension events. Add it if it's missing.
-        default_values = [("ContainerId", get_container_id_from_env()), ("GAVersion", CURRENT_AGENT),
-                          ("OpcodeName", ""), ("EventTid", 0), ("EventPid", 0), ("TaskName", ""), ("KeywordName", "")]
-
         for param in event.parameters:
             # Discard any sys_info parameters already in the event, since they will be overwritten
             if param.name in sysinfo_names:
@@ -337,10 +327,7 @@ class MonitorHandler(object):
 
         # Add sys_info params populated by the agent
         final_parameters.extend(self.sysinfo)
-
-        for default_value in default_values:
-            if default_value[0] not in event:
-                final_parameters.append(TelemetryEventParam(default_value[0], default_value[1]))
+        final_parameters = EventLogger.add_default_parameters_to_event(final_parameters, set_values_for_agent=False)
 
         event.parameters = final_parameters
 


Test patch:
diff --git a/tests/common/test_event.py b/tests/common/test_event.py
index 9f0f7747..c5cb974e 100644
--- a/tests/common/test_event.py
+++ b/tests/common/test_event.py
@@ -23,11 +23,11 @@ import threading
 from datetime import datetime, timedelta
 
 from azurelinuxagent.common import event, logger
-from azurelinuxagent.common.event import add_event, \
-    WALAEventOperation, elapsed_milliseconds, report_metric
+from azurelinuxagent.common.event import add_event, report_metric, WALAEventOperation, elapsed_milliseconds, EventLogger
 from azurelinuxagent.common.exception import EventError
-from azurelinuxagent.common.future import ustr
+from azurelinuxagent.common.future import ustr, OrderedDict
 from azurelinuxagent.common.protocol.wire import GoalState
+from azurelinuxagent.common.telemetryevent import TelemetryEventParam
 from azurelinuxagent.common.utils import fileutil
 from azurelinuxagent.common.utils.extensionprocessutil import read_output
 from azurelinuxagent.common.version import CURRENT_VERSION, CURRENT_AGENT
@@ -437,6 +437,108 @@ class TestEvent(AgentTestCase):
         utc_start = datetime.utcnow() + timedelta(days=1)
         self.assertEqual(0, elapsed_milliseconds(utc_start))
 
+    def _assert_default_params_get_correctly_added(self, param_list_actual, parameters_expected):
+        default_parameters_expected_names = set(parameters_expected.keys())
+
+        # Converting list of TelemetryEventParam into a dictionary, for easier look up of values.
+        param_list_dict = OrderedDict([(param.name, param.value) for param in param_list_actual])
+
+        counter = 0
+        for p in default_parameters_expected_names:
+            self.assertIn(p, param_list_dict)
+            self.assertEqual(param_list_dict[p], parameters_expected[p])
+            counter += 1
+
+        self.assertEqual(len(default_parameters_expected_names), counter)
+
+    @patch("azurelinuxagent.common.event.get_container_id_from_env", return_value="TEST_CONTAINER_ID")
+    def test_add_default_parameters_to_extension_event(self, *args):
+        default_parameters_expected = {"GAVersion": CURRENT_AGENT, 'ContainerId': "TEST_CONTAINER_ID", 'OpcodeName': "",
+                                       'EventTid': 0, 'EventPid': 0, "TaskName": "", "KeywordName": ""}
+
+        # When no values are populated in the TelemetryEventParamList.
+        extension_param_list_empty = EventLogger.add_default_parameters_to_event([], set_values_for_agent=False)
+        self._assert_default_params_get_correctly_added(extension_param_list_empty, default_parameters_expected)
+
+        # When some values are already populated in the TelemetryEventParamList.
+        extension_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                          TelemetryEventParam('Version', CURRENT_VERSION),
+                                          TelemetryEventParam('Operation', "DummyOperation"),
+                                          TelemetryEventParam('OperationSuccess', True),
+                                          TelemetryEventParam('Message', "TestMessage"),
+                                          TelemetryEventParam('Duration', 10), TelemetryEventParam('ExtensionType', ''),
+                                          TelemetryEventParam('OpcodeName', '')]
+        extension_param_list_with_defaults = EventLogger.add_default_parameters_to_event(extension_param_list_populated,
+                                                                                         set_values_for_agent=False)
+        self._assert_default_params_get_correctly_added(extension_param_list_with_defaults, default_parameters_expected)
+
+        parameters_expected = {"GAVersion": CURRENT_AGENT, 'ContainerId': "TEST_CONTAINER_ID", 'OpcodeName': "",
+                               'EventTid': 100, 'EventPid': 10, "TaskName": "", "KeywordName": ""}
+
+        # When some values are already populated in the TelemetryEventParamList.
+        extension_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                          TelemetryEventParam('Version', CURRENT_VERSION),
+                                          TelemetryEventParam('Operation', "DummyOperation"),
+                                          TelemetryEventParam('OperationSuccess', True),
+                                          TelemetryEventParam('Message', "TestMessage"),
+                                          TelemetryEventParam('Duration', 10),
+                                          TelemetryEventParam('ExtensionType', ''),
+                                          TelemetryEventParam('OpcodeName', ''),
+                                          TelemetryEventParam('EventTid', 100),
+                                          TelemetryEventParam('EventPid', 10)]
+        extension_param_list_with_defaults = EventLogger.add_default_parameters_to_event(extension_param_list_populated,
+                                                                                         set_values_for_agent=False)
+        self._assert_default_params_get_correctly_added(extension_param_list_with_defaults,
+                                                        parameters_expected)
+
+    @patch("threading.Thread.getName", return_value="HelloWorldTask")
+    @patch('os.getpid', return_value=42)
+    @patch("azurelinuxagent.common.event.get_container_id_from_env", return_value="TEST_CONTAINER_ID")
+    @patch("azurelinuxagent.common.event.datetime")
+    def test_add_default_parameters_to_agent_event(self, patch_datetime, *args):
+        patch_datetime.utcnow = Mock(return_value=datetime.strptime("2019-01-01 01:30:00",
+                                                                    '%Y-%m-%d %H:%M:%S'))
+        default_parameters_expected = {"GAVersion": CURRENT_AGENT,
+                                       'ContainerId': "TEST_CONTAINER_ID",
+                                       'OpcodeName': "2019-01-01 01:30:00",
+                                       'EventTid': threading.current_thread().ident,
+                                       'EventPid': 42,
+                                       "TaskName": "HelloWorldTask",
+                                       "KeywordName": ""}
+        agent_param_list_empty = EventLogger.add_default_parameters_to_event([], set_values_for_agent=True)
+        self._assert_default_params_get_correctly_added(agent_param_list_empty, default_parameters_expected)
+
+        # When some values are already populated in the TelemetryEventParamList.
+        agent_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                      TelemetryEventParam('Version', CURRENT_VERSION),
+                                      TelemetryEventParam('Operation', "DummyOperation"),
+                                      TelemetryEventParam('OperationSuccess', True),
+                                      TelemetryEventParam('Message', "TestMessage"),
+                                      TelemetryEventParam('Duration', 10), TelemetryEventParam('ExtensionType', ''),
+                                      TelemetryEventParam('OpcodeName', '')]
+        agent_param_list_after_defaults_added = EventLogger.add_default_parameters_to_event(agent_param_list_populated,
+                                                                                            set_values_for_agent=True)
+        self._assert_default_params_get_correctly_added(agent_param_list_after_defaults_added,
+                                                        default_parameters_expected)
+
+        # When some values are already populated in the TelemetryEventParamList, along with some
+        # default values already populated and it should be replaced, when set_values_for_agent=True
+        agent_param_list_populated = [TelemetryEventParam('Name', "DummyExtension"),
+                                      TelemetryEventParam('Version', CURRENT_VERSION),
+                                      TelemetryEventParam('Operation', "DummyOperation"),
+                                      TelemetryEventParam('OperationSuccess', True),
+                                      TelemetryEventParam('Message', "TestMessage"),
+                                      TelemetryEventParam('Duration', 10), TelemetryEventParam('ExtensionType', ''),
+                                      TelemetryEventParam('OpcodeName', 'timestamp'),
+                                      TelemetryEventParam('ContainerId', 'SOME-CONTAINER'),
+                                      TelemetryEventParam('EventTid', 10101010), TelemetryEventParam('EventPid', 110),
+                                      TelemetryEventParam('TaskName', 'Test-TaskName')]
+
+        agent_param_list_after_defaults_added = EventLogger.add_default_parameters_to_event(agent_param_list_populated,
+                                                                                            set_values_for_agent=True)
+        self._assert_default_params_get_correctly_added(agent_param_list_after_defaults_added,
+                                                        default_parameters_expected)
+
 
 class TestMetrics(AgentTestCase):
     @patch('azurelinuxagent.common.event.EventLogger.save_event')
diff --git a/tests/ga/test_monitor.py b/tests/ga/test_monitor.py
index bef5fbce..f4e713a8 100644
--- a/tests/ga/test_monitor.py
+++ b/tests/ga/test_monitor.py
@@ -40,15 +40,16 @@ from azurelinuxagent.common.future import ustr
 from azurelinuxagent.common.osutil.default import BASE_CGROUPS, DefaultOSUtil
 from azurelinuxagent.common.protocol.imds import ComputeInfo
 from azurelinuxagent.common.protocol.restapi import VMInfo
-from azurelinuxagent.common.protocol.wire import ExtHandler, ExtHandlerProperties, WireProtocol
-from azurelinuxagent.common.telemetryevent import TelemetryEventParam, TelemetryEvent
-from azurelinuxagent.common.utils import restutil, fileutil
-from azurelinuxagent.common.version import AGENT_VERSION, CURRENT_VERSION, AGENT_NAME, CURRENT_AGENT
+from azurelinuxagent.common.protocol.wire import ExtHandler, ExtHandlerProperties
+from azurelinuxagent.common.protocol.wire import WireProtocol
+from azurelinuxagent.common.telemetryevent import TelemetryEvent, TelemetryEventParam
+from azurelinuxagent.common.utils import fileutil, restutil
+from azurelinuxagent.common.version import AGENT_NAME, CURRENT_VERSION, AGENT_VERSION, CURRENT_AGENT
 from azurelinuxagent.ga.exthandlers import ExtHandlerInstance
-from azurelinuxagent.ga.monitor import parse_xml_event, get_monitor_handler, MonitorHandler, \
-    generate_extension_metrics_telemetry_dictionary, parse_json_event
+from azurelinuxagent.ga.monitor import generate_extension_metrics_telemetry_dictionary, get_monitor_handler, \
+    MonitorHandler, parse_json_event, parse_xml_event
 from tests.common.test_cgroupstelemetry import make_new_cgroup
-from tests.protocol.mockwiredata import WireProtocolData, DATA_FILE
+from tests.protocol.mockwiredata import DATA_FILE, WireProtocolData
 from tests.tools import Mock, MagicMock, patch, load_data, AgentTestCase, data_dir, are_cgroups_enabled, \
     i_am_root, skip_if_predicate_false, is_trusty_in_travis, skip_if_predicate_true
 
@@ -626,8 +627,9 @@ class TestEventMonitoring(AgentTestCase):
         # Validating the crafted message by the collect_and_send_events call.
         self.assertEqual(1, patch_send_event.call_count)
         send_event_call_args = protocol.client.send_event.call_args[0]
-        sample_message = '<Event id="1">' \
-                         '<![CDATA[<Param Name="Name" Value="DummyExtension" T="mt:wstr" />' \
+
+        sample_message = '<Event id="1"><![CDATA[' \
+                         '<Param Name="Name" Value="DummyExtension" T="mt:wstr" />' \
                          '<Param Name="Version" Value="{0}" T="mt:wstr" />' \
                          '<Param Name="IsInternal" Value="False" T="mt:bool" />' \
                          '<Param Name="Operation" Value="Unknown" T="mt:wstr" />' \
@@ -650,13 +652,13 @@ class TestEventMonitoring(AgentTestCase):
                          '<Param Name="ResourceGroupName" Value="DummyRG" T="mt:wstr" />' \
                          '<Param Name="VMId" Value="DummyVmId" T="mt:wstr" />' \
                          '<Param Name="ImageOrigin" Value="1" T="mt:uint64" />' \
-                         '<Param Name="ContainerId" Value="c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2" T="mt:wstr" />' \
                          '<Param Name="GAVersion" Value="{1}" T="mt:wstr" />' \
+                         '<Param Name="ContainerId" Value="c6d5526c-5ac2-4200-b6e2-56f2b70c5ab2" T="mt:wstr" />' \
                          '<Param Name="EventTid" Value="0" T="mt:uint64" />' \
                          '<Param Name="EventPid" Value="0" T="mt:uint64" />' \
                          '<Param Name="TaskName" Value="" T="mt:wstr" />' \
-                         '<Param Name="KeywordName" Value="" T="mt:wstr" />]]>' \
-                         '</Event>'.format(AGENT_VERSION, CURRENT_AGENT)
+                         '<Param Name="KeywordName" Value="" T="mt:wstr" />' \
+                         ']]></Event>'.format(AGENT_VERSION, CURRENT_AGENT)
 
         self.maxDiff = None
         self.assertEqual(sample_message, send_event_call_args[1])