def testGetStatisticsMultpleInstances(self, ec2InstanceMetricGetterMock, getAutostackFromMetricMock, _engineFactoryMock): metricID = "abc" class MetricRowSpec(object): uid = None datasource = None metricRowMock = Mock(spec_set=MetricRowSpec, uid=metricID, datasource="autostack") autostackMock = Mock() getAutostackFromMetricMock.return_value = autostackMock metricGetterMock = Mock() ec2InstanceMetricGetterMock.return_value = metricGetterMock metricGetterMock.collectMetricStatistics.return_value = [ InstanceMetricData(instanceID="tempID1", records=[ MetricRecord(timestamp=None, value={ "min": 5.0, "max": 20.0 }) ]), InstanceMetricData(instanceID="tempID2", records=[ MetricRecord(timestamp=None, value={ "min": 15.0, "max": 30.0 }) ]), ] # Call the function under test stats = aggregation.getStatistics(metricRowMock) # Validate stats self.assertSetEqual(set(stats.keys()), set(("min", "max"))) # Make sure to include 20% buffer on range self.assertAlmostEqual(stats["min"], 7.0) self.assertAlmostEqual(stats["max"], 28.0) # Validate mocks were called correctly self.assertEqual(getAutostackFromMetricMock.call_args[0][1], metricID) metricGetterMock.collectMetricStatistics.assert_called_once_with( autostackMock, metricRowMock) metricGetterMock.close.assert_called_once()
def testAggregationNoValues(self): """Single metric with no values.""" slices = ( InstanceMetricData("id", ()), ) result = aggregation.aggregate(slices) self.assertEqual(len(result), 0)
def testAggregationSingleValue(self): """Single metric with single value.""" timestamp = datetime.datetime.utcnow() slices = (InstanceMetricData("id", (MetricRecord(timestamp, 100.0), )), ) result = aggregation.aggregate(slices) self.assertEqual(len(result), 1) self.assertIsInstance(result[0], tuple) self.assertSequenceEqual(result[0], (timestamp, 100.0))
def testAggregationMultipleMetricsAlignedSum(self): """Multiple metrics with matching timestamps.""" timestamp2 = datetime.datetime.utcnow() timestamp1 = timestamp2 - datetime.timedelta(minutes=5) slices = ( InstanceMetricData("id1", ( MetricRecord(timestamp1, 100.0), MetricRecord(timestamp2, 50.0), )), InstanceMetricData("id2", ( MetricRecord(timestamp1, 80.0), MetricRecord(timestamp2, 30.0), )), ) result = aggregation.aggregate(slices, aggregationFn=sum) self.assertEqual(len(result), 2) self.assertIsInstance(result[0], tuple) self.assertIsInstance(result[1], tuple) self.assertSequenceEqual(result[0], (timestamp1, 180.0)) self.assertSequenceEqual(result[1], (timestamp2, 80.0))
def testAggregationMultipleValues(self): """Single metric with multiple values at different timestamps.""" timestamp2 = datetime.datetime.utcnow() timestamp1 = timestamp2 - datetime.timedelta(minutes=5) slices = (InstanceMetricData("id", ( MetricRecord(timestamp1, 100.0), MetricRecord(timestamp2, 50.0), )), ) result = aggregation.aggregate(slices) self.assertEqual(len(result), 2) self.assertIsInstance(result[0], tuple) self.assertIsInstance(result[1], tuple) self.assertSequenceEqual(result[0], (timestamp1, 100.0)) self.assertSequenceEqual(result[1], (timestamp2, 50.0))
def testAggregationMultipleMetricsMisaligned(self): """Multiple metrics with both matching and non-matching timestamps.""" timestamp3 = datetime.datetime.utcnow() timestamp2 = timestamp3 - datetime.timedelta(minutes=5) timestamp1 = timestamp2 - datetime.timedelta(minutes=5) slices = ( InstanceMetricData("id1", ( MetricRecord(timestamp1, 100.0), MetricRecord(timestamp2, 50.0), )), InstanceMetricData("id2", ( MetricRecord(timestamp2, 80.0), MetricRecord(timestamp3, 30.0), )), ) result = aggregation.aggregate(slices) self.assertEqual(len(result), 3) self.assertIsInstance(result[0], tuple) self.assertIsInstance(result[1], tuple) self.assertIsInstance(result[2], tuple) self.assertSequenceEqual(result[0], (timestamp1, 100.0)) self.assertSequenceEqual(result[1], (timestamp2, 65.0)) self.assertSequenceEqual(result[2], (timestamp3, 30.0))
def testMetricNotFoundFromSetLastTimestamp(self, engineMock, repoMock, ec2InstanceMetricGetterMock, _metricStreamerMock): """Test handling of ObjectNotFoundError when calling repository.setMetricLastTimestamp in _processAutostackMetricRequests. In this case, we expect _processAutostackMetricRequests to skip this collection and continue processing the next one(s) """ # Ignore attemting to look for MySQL transient errors. # We're not testing those here. repoMock.retryOnTransientErrors.side_effect = lambda f: f # Define metric to skip over errMetric = Mock(spec_set=self.MetricRowSpec) errMetric.name = "errMetric" errInstanceID = "i-00000" errRefID = 0 # index into requests sequence errRequest = AutostackMetricRequest( refID=errRefID, autostack=Mock(spec_set=self.AutostackRowSpec), metric=errMetric) errMetricRecord = MetricRecord(timestamp=datetime.datetime.utcnow(), value=2) errData = InstanceMetricData(instanceID=errInstanceID, records=[errMetricRecord]) errCollection = MetricCollection(refID=errRefID, slices=[errData], timeRange=self.timeRange, nextMetricTime=self.timeRange.end) # Define "ok" metric okMetric = Mock(spec_set=self.MetricRowSpec) okMetric.name = "okMetric" okInstanceID = "i-11111" okRefID = 1 # index into requests sequence okRequest = AutostackMetricRequest( refID=okRefID, autostack=Mock(spec_set=self.AutostackRowSpec), metric=okMetric) okDataValue = 111 okMetricRecord = MetricRecord(timestamp=datetime.datetime.utcnow(), value=okDataValue) okData = InstanceMetricData(instanceID=okInstanceID, records=[okMetricRecord]) okCollection = MetricCollection(refID=okRefID, slices=[okData], timeRange=self.timeRange, nextMetricTime=self.timeRange.end) # Make setMetricLastTimestamp error on first call (error metric) and pass # on second call (ok metric) repoMock.setMetricLastTimestamp.side_effect = ( app_exceptions.ObjectNotFoundError("Expected: things happen"), None) requests = [errRequest, okRequest] collections = [errCollection, okCollection] metricGetterInstanceMock = ec2InstanceMetricGetterMock.return_value metricGetterInstanceMock.collectMetricData.return_value = iter( collections) streamedData = [] _metricStreamerMock.return_value.streamMetricData.side_effect = ( lambda data, *args, **kwargs: streamedData.append(data)) aggSvc = aggregator_service.AggregatorService() with patch.object(aggregator_service, "getAggregationFn", autospec=True, return_value=None): aggSvc._processAutostackMetricRequests( engine=engineMock, requests=requests, modelSwapper=Mock(spec_set=ModelSwapperInterface)) self.assertEqual(len(streamedData), 1) self.assertEqual(len(streamedData[0]), 1) self.assertEqual(streamedData[0][0][1], okDataValue)