|
| 1 | +#!/usr/bin/env python |
| 2 | +""" |
| 3 | +Unit tests for metrics_ext_utils/metrics_ext_handler.py |
| 4 | +""" |
| 5 | + |
| 6 | +import sys |
| 7 | +import os |
| 8 | +import json |
| 9 | +import unittest |
| 10 | +from unittest.mock import patch, MagicMock, mock_open |
| 11 | + |
| 12 | +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) |
| 13 | + |
| 14 | +# Mock Linux-only modules before importing the handler |
| 15 | +for mod_name in ('grp', 'pwd'): |
| 16 | + if mod_name not in sys.modules: |
| 17 | + sys.modules[mod_name] = MagicMock() |
| 18 | + |
| 19 | +import metrics_ext_utils.metrics_constants as metrics_constants |
| 20 | +from metrics_ext_utils.metrics_ext_handler import ( |
| 21 | + create_metrics_extension_conf, |
| 22 | + create_custom_metrics_conf, |
| 23 | + get_metrics_extension_service_name, |
| 24 | + get_arm_domain, |
| 25 | + ARMDomainMap, |
| 26 | + PublicCloudName, |
| 27 | + FairfaxCloudName, |
| 28 | + MooncakeCloudName, |
| 29 | + USNatCloudName, |
| 30 | + USSecCloudName, |
| 31 | +) |
| 32 | + |
| 33 | + |
| 34 | +class TestCreateMetricsExtensionConf(unittest.TestCase): |
| 35 | + """Tests for create_metrics_extension_conf.""" |
| 36 | + |
| 37 | + def test_contains_resource_id(self): |
| 38 | + resource_id = "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm1" |
| 39 | + conf = create_metrics_extension_conf(resource_id, "https://login.microsoftonline.com/tenant1") |
| 40 | + conf_json = json.loads(conf) |
| 41 | + self.assertEqual(conf_json["azureResourceId"], resource_id) |
| 42 | + |
| 43 | + def test_contains_aad_authority(self): |
| 44 | + aad_url = "https://login.microsoftonline.com/tenant1" |
| 45 | + conf = create_metrics_extension_conf("/sub/rg/vm1", aad_url) |
| 46 | + conf_json = json.loads(conf) |
| 47 | + self.assertEqual(conf_json["aadAuthority"], aad_url) |
| 48 | + |
| 49 | + def test_valid_json(self): |
| 50 | + conf = create_metrics_extension_conf("/some/id", "https://aad.url") |
| 51 | + conf_json = json.loads(conf) |
| 52 | + self.assertIn("timeToTerminateInMs", conf_json) |
| 53 | + self.assertIn("maxPublicationMetricsPerMinute", conf_json) |
| 54 | + self.assertEqual(conf_json["publicationIntervalInSec"], 60) |
| 55 | + |
| 56 | + def test_publish_min_max_default_true(self): |
| 57 | + conf = create_metrics_extension_conf("/id", "https://aad") |
| 58 | + conf_json = json.loads(conf) |
| 59 | + self.assertTrue(conf_json["publishMinMaxByDefault"]) |
| 60 | + |
| 61 | + |
| 62 | +class TestCreateCustomMetricsConf(unittest.TestCase): |
| 63 | + """Tests for create_custom_metrics_conf.""" |
| 64 | + |
| 65 | + def test_default_gig_endpoint(self): |
| 66 | + conf = create_custom_metrics_conf("westus2") |
| 67 | + conf_json = json.loads(conf) |
| 68 | + self.assertEqual(conf_json["homeStampGslbHostname"], "westus2.monitoring.azure.com") |
| 69 | + self.assertIn("https://westus2.monitoring.azure.com/api/v1/ingestion/ingest", |
| 70 | + conf_json["endpointsForClientPublication"]) |
| 71 | + |
| 72 | + def test_custom_gig_endpoint(self): |
| 73 | + custom_ep = "https://custom.endpoint.example.com" |
| 74 | + conf = create_custom_metrics_conf("eastus", gig_endpoint=custom_ep) |
| 75 | + conf_json = json.loads(conf) |
| 76 | + self.assertEqual(conf_json["homeStampGslbHostname"], "custom.endpoint.example.com") |
| 77 | + self.assertIn(custom_ep + "/api/v1/ingestion/ingest", |
| 78 | + conf_json["endpointsForClientPublication"]) |
| 79 | + |
| 80 | + def test_valid_json_structure(self): |
| 81 | + conf = create_custom_metrics_conf("centralus") |
| 82 | + conf_json = json.loads(conf) |
| 83 | + self.assertIn("version", conf_json) |
| 84 | + self.assertEqual(conf_json["version"], 17) |
| 85 | + |
| 86 | + |
| 87 | +class TestGetMetricsExtensionServiceName(unittest.TestCase): |
| 88 | + """Tests for get_metrics_extension_service_name.""" |
| 89 | + |
| 90 | + def test_lad_service_name(self): |
| 91 | + name = get_metrics_extension_service_name(True) |
| 92 | + self.assertEqual(name, metrics_constants.lad_metrics_extension_service_name) |
| 93 | + |
| 94 | + def test_ama_service_name(self): |
| 95 | + name = get_metrics_extension_service_name(False) |
| 96 | + self.assertEqual(name, metrics_constants.metrics_extension_service_name) |
| 97 | + |
| 98 | + |
| 99 | +class TestGetArmDomain(unittest.TestCase): |
| 100 | + """Tests for get_arm_domain.""" |
| 101 | + |
| 102 | + def test_public_cloud(self): |
| 103 | + domain = get_arm_domain("AzurePublicCloud") |
| 104 | + self.assertEqual(domain, "management.azure.com") |
| 105 | + |
| 106 | + def test_fairfax_cloud(self): |
| 107 | + domain = get_arm_domain("AzureUSGovernmentCloud") |
| 108 | + self.assertEqual(domain, "management.usgovcloudapi.net") |
| 109 | + |
| 110 | + def test_mooncake_cloud(self): |
| 111 | + domain = get_arm_domain("AzureChinaCloud") |
| 112 | + self.assertEqual(domain, "management.chinacloudapi.cn") |
| 113 | + |
| 114 | + def test_usnat_cloud(self): |
| 115 | + domain = get_arm_domain("USNat") |
| 116 | + self.assertEqual(domain, "management.azure.eaglex.ic.gov") |
| 117 | + |
| 118 | + def test_ussec_cloud(self): |
| 119 | + domain = get_arm_domain("USSec") |
| 120 | + self.assertEqual(domain, "management.azure.microsoft.scloud") |
| 121 | + |
| 122 | + def test_unknown_cloud_raises(self): |
| 123 | + with self.assertRaises(Exception) as ctx: |
| 124 | + get_arm_domain("UnknownCloud") |
| 125 | + self.assertIn("Unknown cloud environment", str(ctx.exception)) |
| 126 | + |
| 127 | + @patch('metrics_ext_utils.metrics_ext_handler.get_arca_endpoints_from_himds') |
| 128 | + def test_arca_cloud(self, mock_arca): |
| 129 | + mock_arca.return_value = ("https://arm.azurestackcloud.example.com", "https://mcs.example.com") |
| 130 | + domain = get_arm_domain("AzureStackCloud") |
| 131 | + self.assertEqual(domain, "arm.azurestackcloud.example.com") |
| 132 | + |
| 133 | + |
| 134 | +class TestGetMetricsExtensionServicePath(unittest.TestCase): |
| 135 | + """Tests for get_metrics_extension_service_path.""" |
| 136 | + |
| 137 | + @patch('os.path.exists') |
| 138 | + def test_lad_lib_systemd(self, mock_exists): |
| 139 | + from metrics_ext_utils.metrics_ext_handler import get_metrics_extension_service_path |
| 140 | + mock_exists.side_effect = lambda p: p == "/lib/systemd/system/" |
| 141 | + path = get_metrics_extension_service_path(True) |
| 142 | + self.assertEqual(path, metrics_constants.lad_metrics_extension_service_path) |
| 143 | + |
| 144 | + @patch('os.path.exists') |
| 145 | + def test_lad_usr_lib_systemd(self, mock_exists): |
| 146 | + from metrics_ext_utils.metrics_ext_handler import get_metrics_extension_service_path |
| 147 | + mock_exists.side_effect = lambda p: p == "/usr/lib/systemd/system/" |
| 148 | + path = get_metrics_extension_service_path(True) |
| 149 | + self.assertEqual(path, metrics_constants.lad_metrics_extension_service_path_usr_lib) |
| 150 | + |
| 151 | + @patch('os.path.exists') |
| 152 | + def test_lad_no_systemd_raises(self, mock_exists): |
| 153 | + from metrics_ext_utils.metrics_ext_handler import get_metrics_extension_service_path |
| 154 | + mock_exists.return_value = False |
| 155 | + with self.assertRaises(Exception): |
| 156 | + get_metrics_extension_service_path(True) |
| 157 | + |
| 158 | + @patch('os.path.exists') |
| 159 | + def test_ama_etc_systemd(self, mock_exists): |
| 160 | + from metrics_ext_utils.metrics_ext_handler import get_metrics_extension_service_path |
| 161 | + mock_exists.side_effect = lambda p: p == "/etc/systemd/system" |
| 162 | + path = get_metrics_extension_service_path(False) |
| 163 | + self.assertEqual(path, metrics_constants.metrics_extension_service_path_etc) |
| 164 | + |
| 165 | + @patch('os.path.exists') |
| 166 | + def test_ama_no_systemd_raises(self, mock_exists): |
| 167 | + from metrics_ext_utils.metrics_ext_handler import get_metrics_extension_service_path |
| 168 | + mock_exists.return_value = False |
| 169 | + with self.assertRaises(Exception): |
| 170 | + get_metrics_extension_service_path(False) |
| 171 | + |
| 172 | + |
| 173 | +class TestIsRunning(unittest.TestCase): |
| 174 | + """Tests for is_running (metrics).""" |
| 175 | + |
| 176 | + @patch('subprocess.Popen') |
| 177 | + def test_returns_true_when_process_found(self, mock_popen): |
| 178 | + from metrics_ext_utils.metrics_ext_handler import is_running |
| 179 | + mock_proc = MagicMock() |
| 180 | + mock_proc.communicate.return_value = ( |
| 181 | + b"/opt/microsoft/azuremonitoragent/bin/MetricsExtension --args", b"" |
| 182 | + ) |
| 183 | + mock_popen.return_value = mock_proc |
| 184 | + self.assertTrue(is_running(False)) |
| 185 | + |
| 186 | + @patch('subprocess.Popen') |
| 187 | + def test_returns_false_when_process_not_found(self, mock_popen): |
| 188 | + from metrics_ext_utils.metrics_ext_handler import is_running |
| 189 | + mock_proc = MagicMock() |
| 190 | + mock_proc.communicate.return_value = (b"", b"") |
| 191 | + mock_popen.return_value = mock_proc |
| 192 | + self.assertFalse(is_running(False)) |
| 193 | + |
| 194 | + |
| 195 | +class TestGetHandlerVars(unittest.TestCase): |
| 196 | + """Tests for get_handler_vars in metrics_ext_handler.""" |
| 197 | + |
| 198 | + @patch('os.path.exists') |
| 199 | + def test_returns_empty_when_no_handler_env(self, mock_exists): |
| 200 | + from metrics_ext_utils.metrics_ext_handler import get_handler_vars |
| 201 | + mock_exists.return_value = False |
| 202 | + log_folder, config_folder = get_handler_vars() |
| 203 | + self.assertEqual(log_folder, "") |
| 204 | + self.assertEqual(config_folder, "") |
| 205 | + |
| 206 | + @patch('os.path.exists', return_value=True) |
| 207 | + @patch('builtins.open', mock_open(read_data=json.dumps([{ |
| 208 | + "handlerEnvironment": { |
| 209 | + "logFolder": "/var/log/azure/ext", |
| 210 | + "configFolder": "/etc/azure/ext" |
| 211 | + } |
| 212 | + }]))) |
| 213 | + def test_parses_handler_env_list(self, mock_exists): |
| 214 | + from metrics_ext_utils.metrics_ext_handler import get_handler_vars |
| 215 | + log_folder, config_folder = get_handler_vars() |
| 216 | + self.assertEqual(log_folder, "/var/log/azure/ext") |
| 217 | + self.assertEqual(config_folder, "/etc/azure/ext") |
| 218 | + |
| 219 | + |
| 220 | +if __name__ == '__main__': |
| 221 | + unittest.main() |
0 commit comments