1# Copyright 2015 Cloudbase Solutions Srl 2# All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); you may 5# not use this file except in compliance with the License. You may obtain 6# a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13# License for the specific language governing permissions and limitations 14# under the License. 15 16from unittest import mock 17 18from os_win import exceptions 19from os_win.tests.unit import test_base 20from os_win.utils import _wqlutils 21from os_win.utils.compute import vmutils 22from os_win.utils.metrics import metricsutils 23from os_win import utilsfactory 24 25 26class MetricsUtilsTestCase(test_base.OsWinBaseTestCase): 27 """Unit tests for the Hyper-V MetricsUtils class.""" 28 29 _FAKE_RET_VAL = 0 30 _FAKE_PORT = "fake's port name" 31 32 _autospec_classes = [ 33 vmutils.VMUtils, 34 ] 35 36 def setUp(self): 37 super(MetricsUtilsTestCase, self).setUp() 38 39 mock.patch.object(utilsfactory, 'get_vmutils', 40 mock.Mock(return_value=vmutils.VMUtils)).start() 41 42 self.utils = metricsutils.MetricsUtils() 43 self.utils._conn_attr = mock.MagicMock() 44 45 def test_cache_metrics_defs(self): 46 mock_metric_def = mock.Mock(ElementName=mock.sentinel.elementname) 47 self.utils._conn.CIM_BaseMetricDefinition.return_value = [ 48 mock_metric_def] 49 self.utils._cache_metrics_defs() 50 expected_cache_metrics = {mock.sentinel.elementname: mock_metric_def} 51 self.assertEqual(expected_cache_metrics, self.utils._metrics_defs_obj) 52 53 @mock.patch.object(metricsutils.MetricsUtils, '_enable_metrics') 54 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_resources') 55 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm') 56 def test_enable_vm_metrics_collection( 57 self, mock_get_vm, mock_get_vm_resources, mock_enable_metrics): 58 mock_vm = mock_get_vm.return_value 59 mock_disk = mock.MagicMock() 60 mock_dvd = mock.MagicMock( 61 ResourceSubType=self.utils._DVD_DISK_RES_SUB_TYPE) 62 mock_get_vm_resources.return_value = [mock_disk, mock_dvd] 63 64 self.utils.enable_vm_metrics_collection(mock.sentinel.vm_name) 65 66 metrics_names = [self.utils._CPU_METRICS, 67 self.utils._MEMORY_METRICS] 68 mock_enable_metrics.assert_has_calls( 69 [mock.call(mock_disk), mock.call(mock_vm, metrics_names)]) 70 71 @mock.patch.object(metricsutils.MetricsUtils, '_enable_metrics') 72 def test_enable_disk_metrics_collection(self, mock_enable_metrics): 73 mock_get_disk = ( 74 self.utils._vmutils._get_mounted_disk_resource_from_path) 75 76 self.utils.enable_disk_metrics_collection( 77 mock.sentinel.disk_path, 78 mock.sentinel.is_physical, 79 mock.sentinel.serial) 80 81 mock_get_disk.assert_called_once_with( 82 mock.sentinel.disk_path, 83 is_physical=mock.sentinel.is_physical, 84 serial=mock.sentinel.serial) 85 mock_enable_metrics.assert_called_once_with(mock_get_disk.return_value) 86 87 @mock.patch.object(metricsutils.MetricsUtils, '_enable_metrics') 88 @mock.patch.object(metricsutils.MetricsUtils, '_get_switch_port') 89 def test_enable_switch_port_metrics_collection(self, mock_get_port, 90 mock_enable_metrics): 91 self.utils.enable_port_metrics_collection(mock.sentinel.port_name) 92 93 mock_get_port.assert_called_once_with(mock.sentinel.port_name) 94 metrics = [self.utils._NET_IN_METRICS, 95 self.utils._NET_OUT_METRICS] 96 mock_enable_metrics.assert_called_once_with( 97 mock_get_port.return_value, metrics) 98 99 def _check_enable_metrics(self, metrics=None, definition=None): 100 mock_element = mock.MagicMock() 101 self.utils._metrics_svc.ControlMetrics.return_value = [0] 102 103 self.utils._enable_metrics(mock_element, metrics) 104 105 self.utils._metrics_svc.ControlMetrics.assert_called_once_with( 106 Subject=mock_element.path_.return_value, 107 Definition=definition, 108 MetricCollectionEnabled=self.utils._METRICS_ENABLED) 109 110 def test_enable_metrics_no_metrics(self): 111 self._check_enable_metrics() 112 113 def test_enable_metrics(self): 114 metrics_name = self.utils._CPU_METRICS 115 metrics_def = mock.MagicMock() 116 self.utils._metrics_defs_obj = {metrics_name: metrics_def} 117 self._check_enable_metrics([metrics_name, mock.sentinel.metrics_name], 118 metrics_def.path_.return_value) 119 120 def test_enable_metrics_exception(self): 121 metric_name = self.utils._CPU_METRICS 122 metric_def = mock.MagicMock() 123 self.utils._metrics_defs_obj = {metric_name: metric_def} 124 125 self.utils._metrics_svc.ControlMetrics.return_value = [1] 126 self.assertRaises(exceptions.OSWinException, 127 self.utils._enable_metrics, 128 mock.MagicMock(), 129 [metric_name]) 130 131 @mock.patch.object(metricsutils.MetricsUtils, '_get_metrics') 132 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_resources') 133 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm') 134 def test_get_cpu_metrics(self, mock_get_vm, mock_get_vm_resources, 135 mock_get_metrics): 136 fake_cpu_count = 2 137 fake_uptime = 1000 138 fake_cpu_metrics_val = 2000 139 140 self.utils._metrics_defs_obj = { 141 self.utils._CPU_METRICS: mock.sentinel.metrics} 142 143 mock_vm = mock_get_vm.return_value 144 mock_vm.OnTimeInMilliseconds = fake_uptime 145 mock_cpu = mock.MagicMock(VirtualQuantity=fake_cpu_count) 146 mock_get_vm_resources.return_value = [mock_cpu] 147 148 mock_metric = mock.MagicMock(MetricValue=fake_cpu_metrics_val) 149 mock_get_metrics.return_value = [mock_metric] 150 151 cpu_metrics = self.utils.get_cpu_metrics(mock.sentinel.vm_name) 152 153 self.assertEqual(3, len(cpu_metrics)) 154 self.assertEqual(fake_cpu_metrics_val, cpu_metrics[0]) 155 self.assertEqual(fake_cpu_count, cpu_metrics[1]) 156 self.assertEqual(fake_uptime, cpu_metrics[2]) 157 158 mock_get_vm.assert_called_once_with(mock.sentinel.vm_name) 159 mock_get_vm_resources.assert_called_once_with( 160 mock.sentinel.vm_name, self.utils._PROCESSOR_SETTING_DATA_CLASS) 161 mock_get_metrics.assert_called_once_with(mock_vm, 162 mock.sentinel.metrics) 163 164 @mock.patch.object(metricsutils.MetricsUtils, '_get_metrics') 165 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm') 166 def test_get_memory_metrics(self, mock_get_vm, mock_get_metrics): 167 mock_vm = mock_get_vm.return_value 168 self.utils._metrics_defs_obj = { 169 self.utils._MEMORY_METRICS: mock.sentinel.metrics} 170 171 metrics_memory = mock.MagicMock() 172 metrics_memory.MetricValue = 3 173 mock_get_metrics.return_value = [metrics_memory] 174 175 response = self.utils.get_memory_metrics(mock.sentinel.vm_name) 176 177 self.assertEqual(3, response) 178 mock_get_vm.assert_called_once_with(mock.sentinel.vm_name) 179 mock_get_metrics.assert_called_once_with(mock_vm, 180 mock.sentinel.metrics) 181 182 @mock.patch.object(_wqlutils, 'get_element_associated_class') 183 @mock.patch.object(metricsutils.MetricsUtils, 184 '_sum_metrics_values_by_defs') 185 @mock.patch.object(metricsutils.MetricsUtils, 186 '_get_metrics_value_instances') 187 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_resources') 188 def test_get_vnic_metrics(self, mock_get_vm_resources, 189 mock_get_value_instances, mock_sum_by_defs, 190 mock_get_element_associated_class): 191 fake_rx_mb = 1000 192 fake_tx_mb = 2000 193 194 self.utils._metrics_defs_obj = { 195 self.utils._NET_IN_METRICS: mock.sentinel.net_in_metrics, 196 self.utils._NET_OUT_METRICS: mock.sentinel.net_out_metrics} 197 198 mock_port = mock.MagicMock(Parent=mock.sentinel.vnic_path) 199 mock_vnic = mock.MagicMock(ElementName=mock.sentinel.element_name, 200 Address=mock.sentinel.address) 201 mock_vnic.path_.return_value = mock.sentinel.vnic_path 202 mock_get_vm_resources.side_effect = [[mock_port], [mock_vnic]] 203 mock_sum_by_defs.return_value = [fake_rx_mb, fake_tx_mb] 204 205 vnic_metrics = list( 206 self.utils.get_vnic_metrics(mock.sentinel.vm_name)) 207 208 self.assertEqual(1, len(vnic_metrics)) 209 self.assertEqual(fake_rx_mb, vnic_metrics[0]['rx_mb']) 210 self.assertEqual(fake_tx_mb, vnic_metrics[0]['tx_mb']) 211 self.assertEqual(mock.sentinel.element_name, 212 vnic_metrics[0]['element_name']) 213 self.assertEqual(mock.sentinel.address, vnic_metrics[0]['address']) 214 215 mock_get_vm_resources.assert_has_calls([ 216 mock.call(mock.sentinel.vm_name, self.utils._PORT_ALLOC_SET_DATA), 217 mock.call(mock.sentinel.vm_name, 218 self.utils._SYNTH_ETH_PORT_SET_DATA)]) 219 mock_get_value_instances.assert_called_once_with( 220 mock_get_element_associated_class.return_value, 221 self.utils._BASE_METRICS_VALUE) 222 mock_sum_by_defs.assert_called_once_with( 223 mock_get_value_instances.return_value, 224 [mock.sentinel.net_in_metrics, mock.sentinel.net_out_metrics]) 225 226 @mock.patch.object(metricsutils.MetricsUtils, '_get_metrics_values') 227 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_resources') 228 def test_get_disk_metrics(self, mock_get_vm_resources, 229 mock_get_metrics_values): 230 fake_read_mb = 1000 231 fake_write_mb = 2000 232 233 self.utils._metrics_defs_obj = { 234 self.utils._DISK_RD_METRICS: mock.sentinel.disk_rd_metrics, 235 self.utils._DISK_WR_METRICS: mock.sentinel.disk_wr_metrics} 236 237 mock_disk = mock.MagicMock(HostResource=[mock.sentinel.host_resource], 238 InstanceID=mock.sentinel.instance_id) 239 mock_get_vm_resources.return_value = [mock_disk] 240 mock_get_metrics_values.return_value = [fake_read_mb, fake_write_mb] 241 242 disk_metrics = list( 243 self.utils.get_disk_metrics(mock.sentinel.vm_name)) 244 245 self.assertEqual(1, len(disk_metrics)) 246 self.assertEqual(fake_read_mb, disk_metrics[0]['read_mb']) 247 self.assertEqual(fake_write_mb, disk_metrics[0]['write_mb']) 248 self.assertEqual(mock.sentinel.instance_id, 249 disk_metrics[0]['instance_id']) 250 self.assertEqual(mock.sentinel.host_resource, 251 disk_metrics[0]['host_resource']) 252 253 mock_get_vm_resources.assert_called_once_with( 254 mock.sentinel.vm_name, 255 self.utils._STORAGE_ALLOC_SETTING_DATA_CLASS) 256 metrics = [mock.sentinel.disk_rd_metrics, 257 mock.sentinel.disk_wr_metrics] 258 mock_get_metrics_values.assert_called_once_with(mock_disk, metrics) 259 260 @mock.patch.object(metricsutils.MetricsUtils, '_get_metrics_values') 261 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_resources') 262 def test_get_disk_latency_metrics(self, mock_get_vm_resources, 263 mock_get_metrics_values): 264 self.utils._metrics_defs_obj = { 265 self.utils._DISK_LATENCY_METRICS: mock.sentinel.metrics} 266 267 mock_disk = mock.MagicMock(HostResource=[mock.sentinel.host_resource], 268 InstanceID=mock.sentinel.instance_id) 269 mock_get_vm_resources.return_value = [mock_disk] 270 mock_get_metrics_values.return_value = [mock.sentinel.latency] 271 272 disk_metrics = list( 273 self.utils.get_disk_latency_metrics(mock.sentinel.vm_name)) 274 275 self.assertEqual(1, len(disk_metrics)) 276 self.assertEqual(mock.sentinel.latency, 277 disk_metrics[0]['disk_latency']) 278 self.assertEqual(mock.sentinel.instance_id, 279 disk_metrics[0]['instance_id']) 280 mock_get_vm_resources.assert_called_once_with( 281 mock.sentinel.vm_name, 282 self.utils._STORAGE_ALLOC_SETTING_DATA_CLASS) 283 mock_get_metrics_values.assert_called_once_with( 284 mock_disk, [mock.sentinel.metrics]) 285 286 @mock.patch.object(metricsutils.MetricsUtils, '_get_metrics_values') 287 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_resources') 288 def test_get_disk_iops_metrics(self, mock_get_vm_resources, 289 mock_get_metrics_values): 290 self.utils._metrics_defs_obj = { 291 self.utils._DISK_IOPS_METRICS: mock.sentinel.metrics} 292 mock_disk = mock.MagicMock(HostResource=[mock.sentinel.host_resource], 293 InstanceID=mock.sentinel.instance_id) 294 mock_get_vm_resources.return_value = [mock_disk] 295 mock_get_metrics_values.return_value = [mock.sentinel.iops] 296 297 disk_metrics = list( 298 self.utils.get_disk_iops_count(mock.sentinel.vm_name)) 299 300 self.assertEqual(1, len(disk_metrics)) 301 self.assertEqual(mock.sentinel.iops, 302 disk_metrics[0]['iops_count']) 303 self.assertEqual(mock.sentinel.instance_id, 304 disk_metrics[0]['instance_id']) 305 mock_get_vm_resources.assert_called_once_with( 306 mock.sentinel.vm_name, 307 self.utils._STORAGE_ALLOC_SETTING_DATA_CLASS) 308 mock_get_metrics_values.assert_called_once_with( 309 mock_disk, [mock.sentinel.metrics]) 310 311 def test_sum_metrics_values(self): 312 mock_metric = mock.MagicMock(MetricValue='100') 313 result = self.utils._sum_metrics_values([mock_metric] * 2) 314 self.assertEqual(200, result) 315 316 def test_sum_metrics_values_by_defs(self): 317 mock_metric = mock.MagicMock(MetricDefinitionId=mock.sentinel.def_id, 318 MetricValue='100') 319 mock_metric_useless = mock.MagicMock(MetricValue='200') 320 mock_metric_def = mock.MagicMock(Id=mock.sentinel.def_id) 321 322 result = self.utils._sum_metrics_values_by_defs( 323 [mock_metric, mock_metric_useless], [None, mock_metric_def]) 324 325 self.assertEqual([0, 100], result) 326 327 def test_get_metrics_value_instances(self): 328 FAKE_CLASS_NAME = "FAKE_CLASS" 329 mock_el_metric = mock.MagicMock() 330 mock_el_metric_2 = mock.MagicMock() 331 mock_el_metric_2.path.return_value = mock.Mock(Class=FAKE_CLASS_NAME) 332 333 self.utils._conn.Msvm_MetricForME.side_effect = [ 334 [], [mock.Mock(Dependent=mock_el_metric_2)]] 335 336 returned = self.utils._get_metrics_value_instances( 337 [mock_el_metric, mock_el_metric_2], FAKE_CLASS_NAME) 338 339 expected_return = [mock_el_metric_2] 340 self.assertEqual(expected_return, returned) 341 342 @mock.patch.object(metricsutils.MetricsUtils, 343 '_sum_metrics_values_by_defs') 344 def test_get_metrics_values(self, mock_sum_by_defs): 345 mock_element = mock.MagicMock() 346 self.utils._conn.Msvm_MetricForME.return_value = [ 347 mock.Mock(Dependent=mock.sentinel.metric), 348 mock.Mock(Dependent=mock.sentinel.another_metric)] 349 350 resulted_metrics_sum = self.utils._get_metrics_values( 351 mock_element, mock.sentinel.metrics_defs) 352 353 self.utils._conn.Msvm_MetricForME.assert_called_once_with( 354 Antecedent=mock_element.path_.return_value) 355 mock_sum_by_defs.assert_called_once_with( 356 [mock.sentinel.metric, mock.sentinel.another_metric], 357 mock.sentinel.metrics_defs) 358 expected_metrics_sum = mock_sum_by_defs.return_value 359 self.assertEqual(expected_metrics_sum, resulted_metrics_sum) 360 361 @mock.patch.object(metricsutils.MetricsUtils, '_filter_metrics') 362 def test_get_metrics(self, mock_filter_metrics): 363 mock_metric = mock.MagicMock() 364 mock_element = mock.MagicMock() 365 self.utils._conn.Msvm_MetricForME.return_value = [mock_metric] 366 367 result = self.utils._get_metrics(mock_element, 368 mock.sentinel.metrics_def) 369 370 self.assertEqual(mock_filter_metrics.return_value, result) 371 self.utils._conn.Msvm_MetricForME.assert_called_once_with( 372 Antecedent=mock_element.path_.return_value) 373 mock_filter_metrics.assert_called_once_with( 374 [mock_metric.Dependent], 375 mock.sentinel.metrics_def) 376 377 def test_filter_metrics(self): 378 mock_metric = mock.MagicMock(MetricDefinitionId=mock.sentinel.def_id) 379 mock_bad_metric = mock.MagicMock() 380 mock_metric_def = mock.MagicMock(Id=mock.sentinel.def_id) 381 382 result = self.utils._filter_metrics([mock_bad_metric, mock_metric], 383 mock_metric_def) 384 385 self.assertEqual([mock_metric], result) 386 387 @mock.patch.object(_wqlutils, 'get_element_associated_class') 388 @mock.patch.object(metricsutils.MetricsUtils, '_get_vm_setting_data') 389 def test_get_vm_resources(self, mock_get_vm_setting_data, 390 mock_get_element_associated_class): 391 result = self.utils._get_vm_resources(mock.sentinel.vm_name, 392 mock.sentinel.resource_class) 393 394 mock_get_vm_setting_data.assert_called_once_with(mock.sentinel.vm_name) 395 vm_setting_data = mock_get_vm_setting_data.return_value 396 mock_get_element_associated_class.assert_called_once_with( 397 self.utils._conn, mock.sentinel.resource_class, 398 element_instance_id=vm_setting_data.InstanceID) 399 self.assertEqual(mock_get_element_associated_class.return_value, 400 result) 401 402 @mock.patch.object(metricsutils.MetricsUtils, '_unique_result') 403 def test_get_vm(self, mock_unique_result): 404 result = self.utils._get_vm(mock.sentinel.vm_name) 405 406 self.assertEqual(mock_unique_result.return_value, result) 407 conn_class = self.utils._conn.Msvm_ComputerSystem 408 conn_class.assert_called_once_with(ElementName=mock.sentinel.vm_name) 409 mock_unique_result.assert_called_once_with(conn_class.return_value, 410 mock.sentinel.vm_name) 411 412 @mock.patch.object(metricsutils.MetricsUtils, '_unique_result') 413 def test_get_switch_port(self, mock_unique_result): 414 result = self.utils._get_switch_port(mock.sentinel.port_name) 415 416 self.assertEqual(mock_unique_result.return_value, result) 417 conn_class = self.utils._conn.Msvm_EthernetPortAllocationSettingData 418 conn_class.assert_called_once_with(ElementName=mock.sentinel.port_name) 419 mock_unique_result.assert_called_once_with(conn_class.return_value, 420 mock.sentinel.port_name) 421 422 @mock.patch.object(metricsutils.MetricsUtils, '_unique_result') 423 def test_get_vm_setting_data(self, mock_unique_result): 424 result = self.utils._get_vm_setting_data(mock.sentinel.vm_name) 425 426 self.assertEqual(mock_unique_result.return_value, result) 427 conn_class = self.utils._conn.Msvm_VirtualSystemSettingData 428 conn_class.assert_called_once_with(ElementName=mock.sentinel.vm_name) 429 mock_unique_result.assert_called_once_with(conn_class.return_value, 430 mock.sentinel.vm_name) 431 432 def test_unique_result_not_found(self): 433 self.assertRaises(exceptions.NotFound, 434 self.utils._unique_result, 435 [], mock.sentinel.resource_name) 436 437 def test_unique_result_duplicate(self): 438 self.assertRaises(exceptions.OSWinException, 439 self.utils._unique_result, 440 [mock.ANY, mock.ANY], mock.sentinel.resource_name) 441 442 def test_unique_result(self): 443 result = self.utils._unique_result([mock.sentinel.obj], 444 mock.sentinel.resource_name) 445 self.assertEqual(mock.sentinel.obj, result) 446