| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| package org.apache.qpid.server.prometheus; |
| |
| import static org.hamcrest.CoreMatchers.equalTo; |
| import static org.hamcrest.CoreMatchers.is; |
| import static org.hamcrest.CoreMatchers.notNullValue; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.Matchers.closeTo; |
| import static org.junit.jupiter.api.Assertions.fail; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| |
| import io.prometheus.client.Collector; |
| |
| import org.hamcrest.Matchers; |
| |
| import org.junit.jupiter.api.BeforeEach; |
| import org.junit.jupiter.api.Test; |
| |
| import org.apache.qpid.server.model.ConfiguredObject; |
| import org.apache.qpid.server.model.ConfiguredObjectStatistic; |
| import org.apache.qpid.server.model.Model; |
| import org.apache.qpid.server.model.StatisticType; |
| import org.apache.qpid.server.model.StatisticUnit; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestAbstractEngineImpl; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestCar; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestDigitalInstrumentPanelImpl; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestElecEngineImpl; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestEngine; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestInstrumentPanel; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestKitCarImpl; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestModel; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestPetrolEngineImpl; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestSensor; |
| import org.apache.qpid.server.model.testmodels.hierarchy.TestTemperatureSensorImpl; |
| import org.apache.qpid.test.utils.UnitTestBase; |
| |
| public class QpidCollectorTest extends UnitTestBase |
| { |
| private static final String CAR_NAME = "myCar"; |
| private static final String ELECTRIC_ENGINE_NAME = "myEngine"; |
| private static final String INSTRUMENT_PANEL_NAME = "instrumentPanel"; |
| private static final String PETROL_ENGINE_NAME = "myPetrolModel"; |
| private static final String SENSOR = "sensor"; |
| private static final int DESIRED_MILEAGE = 100; |
| private static final String QPID_TEST_CAR_MILEAGE_COUNT = "qpid_test_car_mileage_count"; |
| private static final String QPID_TEST_ENGINE_TEMPERATURE_TOTAL = "qpid_test_engine_temperature_total"; |
| private static final String QPID_TEST_SENSOR_ALERT_COUNT = "qpid_test_sensor_alert_count"; |
| private static final String QPID_TEST_CAR_AGE_COUNT = "qpid_test_car_age"; |
| |
| private TestCar<?> _root; |
| private QpidCollector _qpidCollector; |
| private static final StatisticUnit[] UNITS = new StatisticUnit[]{ |
| StatisticUnit.BYTES, |
| StatisticUnit.MESSAGES, |
| StatisticUnit.COUNT, |
| StatisticUnit.ABSOLUTE_TIME, |
| StatisticUnit.TIME_DURATION}; |
| private static final String[] UNIT_SUFFIXES = new String[]{"_bytes", "_messages", "", "", ""}; |
| |
| @BeforeEach |
| public void setUp() |
| { |
| final Model model = TestModel.getInstance(); |
| final Map<String, Object> carAttributes = new HashMap<>(); |
| carAttributes.put(ConfiguredObject.NAME, CAR_NAME); |
| carAttributes.put(ConfiguredObject.TYPE, TestKitCarImpl.TEST_KITCAR_TYPE); |
| |
| @SuppressWarnings("unchecked") final TestCar<?> car = |
| model.getObjectFactory().create(TestCar.class, carAttributes, null); |
| _root = car; |
| _qpidCollector = new QpidCollector(_root, new IncludeDisabledStatisticPredicate(false), s->true); |
| } |
| |
| @Test |
| public void testCollectForHierarchyOfTwoObjects() |
| { |
| createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE); |
| _root.move(DESIRED_MILEAGE); |
| |
| final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect(); |
| |
| final String[] expectedFamilyNames = {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_ENGINE_TEMPERATURE_TOTAL}; |
| final Map<String, Collector.MetricFamilySamples> metricsMap = |
| convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames); |
| |
| final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT); |
| assertMetricFamilySamplesSize(carMetricFamilySamples, 1); |
| final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0); |
| assertThat(carSample.value, closeTo(DESIRED_MILEAGE, 0.01)); |
| assertThat(carSample.labelNames.size(), is(equalTo(0))); |
| |
| final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get( |
| QPID_TEST_ENGINE_TEMPERATURE_TOTAL); |
| assertMetricFamilySamplesSize(engineMetricFamilySamples, 1); |
| final Collector.MetricFamilySamples.Sample engineSample = engineMetricFamilySamples.samples.get(0); |
| assertThat(engineSample.labelNames, is(equalTo(List.of("name")))); |
| assertThat(engineSample.labelValues, is(equalTo(List.of(ELECTRIC_ENGINE_NAME)))); |
| assertThat(engineSample.value, Matchers.closeTo(TestAbstractEngineImpl.TEST_TEMPERATURE, 0.01)); |
| } |
| |
| @Test |
| public void testCollectForHierarchyOfThreeObjects() |
| { |
| final TestInstrumentPanel instrumentPanel = getTestInstrumentPanel(); |
| createTestSensor(instrumentPanel); |
| |
| final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect(); |
| |
| final String[] expectedFamilyNames = |
| {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_SENSOR_ALERT_COUNT}; |
| final Map<String, Collector.MetricFamilySamples> metricsMap = |
| convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames); |
| |
| final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT); |
| assertMetricFamilySamplesSize(carMetricFamilySamples, 1); |
| final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0); |
| assertThat(carSample.labelNames.size(), is(equalTo(0))); |
| assertThat(carSample.labelValues.size(), is(equalTo(0))); |
| assertThat(carSample.value, closeTo(0, 0.01)); |
| |
| final Collector.MetricFamilySamples sensorlMetricFamilySamples = |
| metricsMap.get(QPID_TEST_SENSOR_ALERT_COUNT); |
| assertMetricFamilySamplesSize(sensorlMetricFamilySamples, 1); |
| final Collector.MetricFamilySamples.Sample sensorSample = sensorlMetricFamilySamples.samples.get(0); |
| assertThat(sensorSample.labelNames, is(equalTo(List.of("name", "test_instrument_panel_name")))); |
| assertThat(sensorSample.labelValues, is(equalTo(List.of(SENSOR, INSTRUMENT_PANEL_NAME)))); |
| } |
| |
| @Test |
| public void testCollectForSiblingObjects() |
| { |
| createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE); |
| createTestEngine(PETROL_ENGINE_NAME, TestPetrolEngineImpl.TEST_PETROL_ENGINE_TYPE); |
| |
| final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect(); |
| |
| final String[] expectedFamilyNames = {QPID_TEST_CAR_MILEAGE_COUNT, QPID_TEST_ENGINE_TEMPERATURE_TOTAL}; |
| final Map<String, Collector.MetricFamilySamples> metricsMap = |
| convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames); |
| |
| final Collector.MetricFamilySamples carMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_MILEAGE_COUNT); |
| assertMetricFamilySamplesSize(carMetricFamilySamples, 1); |
| final Collector.MetricFamilySamples.Sample carSample = carMetricFamilySamples.samples.get(0); |
| assertThat(carSample.labelNames.size(), is(equalTo(0))); |
| assertThat(carSample.labelValues.size(), is(equalTo(0))); |
| |
| final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get( |
| QPID_TEST_ENGINE_TEMPERATURE_TOTAL); |
| assertMetricFamilySamplesSize(engineMetricFamilySamples, 2); |
| final String[] engineNames = {PETROL_ENGINE_NAME, ELECTRIC_ENGINE_NAME}; |
| for (String engineName : engineNames) |
| { |
| final Collector.MetricFamilySamples.Sample sample = |
| findSampleByLabelValue(engineMetricFamilySamples, engineName); |
| assertThat(sample.labelNames, is(equalTo(List.of("name")))); |
| assertThat(sample.labelValues, is(equalTo(List.of(engineName)))); |
| assertThat(sample.value, Matchers.closeTo(TestAbstractEngineImpl.TEST_TEMPERATURE, 0.01)); |
| } |
| } |
| |
| @Test |
| public void testCollectWithFilter(){ |
| createTestEngine(ELECTRIC_ENGINE_NAME, TestElecEngineImpl.TEST_ELEC_ENGINE_TYPE); |
| _root.move(DESIRED_MILEAGE); |
| |
| _qpidCollector = new QpidCollector(_root, |
| new IncludeDisabledStatisticPredicate(true), |
| new IncludeMetricPredicate(Set.of(QPID_TEST_CAR_AGE_COUNT))); |
| final List<Collector.MetricFamilySamples> metrics = _qpidCollector.collect(); |
| |
| final String[] expectedFamilyNames = {QPID_TEST_CAR_AGE_COUNT}; |
| final Map<String, Collector.MetricFamilySamples> metricsMap = |
| convertMetricFamilySamplesIntoMapAndAssert(metrics, expectedFamilyNames); |
| |
| |
| final Collector.MetricFamilySamples engineMetricFamilySamples = metricsMap.get(QPID_TEST_CAR_AGE_COUNT); |
| assertMetricFamilySamplesSize(engineMetricFamilySamples, 1); |
| final Collector.MetricFamilySamples.Sample engineSample = engineMetricFamilySamples.samples.get(0); |
| assertThat(engineSample.labelNames, is(equalTo(List.of()))); |
| assertThat(engineSample.labelValues, is(equalTo(List.of()))); |
| assertThat(engineSample.value, Matchers.closeTo(0.0, 0.01)); |
| |
| } |
| |
| |
| private Collector.MetricFamilySamples.Sample findSampleByLabelValue(final Collector.MetricFamilySamples metricFamilySamples, |
| final String nameLabelValue) |
| { |
| final List<Collector.MetricFamilySamples.Sample> found = metricFamilySamples.samples |
| .stream() |
| .filter(s -> s.labelValues != null |
| && s.labelValues.size() > 0 |
| && nameLabelValue.equals(s.labelValues.get(0))) |
| .collect(Collectors.toList()); |
| assertThat(found.size(), is(equalTo(1))); |
| return found.get(0); |
| } |
| |
| private void createTestEngine(final String engineName, final String engineType) |
| { |
| final Map<String, Object> engineAttributes = new HashMap<>(); |
| engineAttributes.put(ConfiguredObject.NAME, engineName); |
| engineAttributes.put(ConfiguredObject.TYPE, engineType); |
| _root.createChild(TestEngine.class, engineAttributes); |
| } |
| |
| private void createTestSensor(final TestInstrumentPanel instrumentPanel) |
| { |
| final Map<String, Object> sensorAttributes = new HashMap<>(); |
| sensorAttributes.put(ConfiguredObject.NAME, SENSOR); |
| sensorAttributes.put(ConfiguredObject.TYPE, TestTemperatureSensorImpl.TEST_TEMPERATURE_SENSOR_TYPE); |
| instrumentPanel.createChild(TestSensor.class, sensorAttributes); |
| } |
| |
| private TestInstrumentPanel getTestInstrumentPanel() |
| { |
| final Map<String, Object> instrumentPanelAttributes = new HashMap<>(); |
| instrumentPanelAttributes.put(ConfiguredObject.NAME, INSTRUMENT_PANEL_NAME); |
| instrumentPanelAttributes.put(ConfiguredObject.TYPE, |
| TestDigitalInstrumentPanelImpl.TEST_DIGITAL_INSTRUMENT_PANEL_TYPE); |
| return _root.createChild(TestInstrumentPanel.class, instrumentPanelAttributes); |
| } |
| |
| private Map<String, Collector.MetricFamilySamples> convertMetricFamilySamplesIntoMap(List<Collector.MetricFamilySamples> metricFamilySamples) |
| { |
| Map<String, Collector.MetricFamilySamples> result = new HashMap<>(); |
| for (Collector.MetricFamilySamples metricFamilySample : metricFamilySamples) |
| { |
| final String name = metricFamilySample.name; |
| |
| if (result.put(name, metricFamilySample) != null) |
| { |
| fail(String.format("Duplicate family name : %s", name)); |
| } |
| } |
| return result; |
| } |
| |
| private void assertMetricFamilySamples(final Collector.MetricFamilySamples metricFamilySamples) |
| { |
| assertThat(metricFamilySamples, is(notNullValue())); |
| assertThat(metricFamilySamples.samples, is(notNullValue())); |
| |
| for (final Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) |
| { |
| assertThat(sample, is(notNullValue())); |
| assertThat(sample.name, is(equalTo(metricFamilySamples.name))); |
| } |
| } |
| |
| |
| private void assertMetricFamilySamplesSize(final Collector.MetricFamilySamples metricFamilySamples, |
| final int expectedSamplesSize) |
| { |
| assertThat(metricFamilySamples.samples.size(), equalTo(expectedSamplesSize)); |
| } |
| |
| private Map<String, Collector.MetricFamilySamples> convertMetricFamilySamplesIntoMapAndAssert(final List<Collector.MetricFamilySamples> metrics, |
| final String[] expectedFamilyNames) |
| { |
| assertThat(metrics.size(), equalTo(expectedFamilyNames.length)); |
| final Map<String, Collector.MetricFamilySamples> metricsMap = convertMetricFamilySamplesIntoMap(metrics); |
| |
| for (String expectedFamily : expectedFamilyNames) |
| { |
| assertMetricFamilySamples(metricsMap.get(expectedFamily)); |
| } |
| return metricsMap; |
| } |
| |
| @Test |
| public void testToSnakeCase() |
| { |
| assertThat(QpidCollector.toSnakeCase("carEngineOilChanges"), is(equalTo("car_engine_oil_changes"))); |
| } |
| |
| @Test |
| public void getFamilyNameForCumulativeStatistic() |
| { |
| for (int i = 0; i < UNITS.length; i++) |
| { |
| final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class); |
| when(statistics.getUnits()).thenReturn(UNITS[i]); |
| when(statistics.getStatisticType()).thenReturn(StatisticType.CUMULATIVE); |
| when(statistics.getName()).thenReturn("diagnosticData"); |
| final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics); |
| final String expectedName = |
| String.format("qpid_test_car_diagnostic_data%s%s", UNIT_SUFFIXES[i], getSuffix(UNITS[i],QpidCollector.COUNT_SUFFIX)); |
| assertThat(String.format("unexpected metric name for units %s", UNITS[i]), |
| familyName, |
| is(equalTo(expectedName))); |
| } |
| } |
| |
| @Test |
| public void getFamilyNameForCumulativeStatisticContainingCountInName() |
| { |
| final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class); |
| when(statistics.getUnits()).thenReturn(StatisticUnit.BYTES); |
| when(statistics.getStatisticType()).thenReturn(StatisticType.CUMULATIVE); |
| when(statistics.getName()).thenReturn("CountOfDiagnosticData"); |
| final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics); |
| assertThat(familyName, is(equalTo("qpid_test_car_count_of_diagnostic_data"))); |
| } |
| |
| @Test |
| public void getFamilyNameForPointInTimeStatistic() |
| { |
| for (int i = 0; i < UNITS.length; i++) |
| { |
| final ConfiguredObjectStatistic<?, ?> statistics = mock(ConfiguredObjectStatistic.class); |
| when(statistics.getUnits()).thenReturn(UNITS[i]); |
| when(statistics.getStatisticType()).thenReturn(StatisticType.POINT_IN_TIME); |
| when(statistics.getName()).thenReturn("diagnosticData"); |
| final String familyName = QpidCollector.getFamilyName(TestCar.class, statistics); |
| |
| final String expectedName = |
| String.format("qpid_test_car_diagnostic_data%s%s", UNIT_SUFFIXES[i], getSuffix(UNITS[i],QpidCollector.TOTAL_SUFFIX)); |
| assertThat(String.format("unexpected metric name for units %s", UNITS[i]), |
| familyName, |
| is(equalTo(expectedName))); |
| } |
| } |
| |
| String getSuffix(final StatisticUnit unit,final String requiredSuffix) |
| { |
| String suffix = "_" + requiredSuffix; |
| if(unit.equals(StatisticUnit.ABSOLUTE_TIME) || unit.equals(StatisticUnit.TIME_DURATION)){ |
| suffix = ""; |
| } |
| return suffix; |
| } |
| } |