org.springframework.boot.actuate.autoconfigure.metrics.PublicMetricsAutoConfigurationTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.boot.actuate.autoconfigure.metrics.PublicMetricsAutoConfigurationTests.java

Source

/*
 * Copyright 2012-2017 the original author or authors.
 *
 * Licensed 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.springframework.boot.actuate.autoconfigure.metrics;

import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.junit.After;
import org.junit.Test;

import org.springframework.boot.actuate.autoconfigure.cache.CacheStatisticsAutoConfiguration;
import org.springframework.boot.actuate.endpoint.CachePublicMetrics;
import org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics;
import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics;
import org.springframework.boot.actuate.endpoint.PublicMetrics;
import org.springframework.boot.actuate.endpoint.RichGaugeReaderPublicMetrics;
import org.springframework.boot.actuate.endpoint.SystemPublicMetrics;
import org.springframework.boot.actuate.endpoint.TomcatPublicMetrics;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.rich.RichGauge;
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
import org.springframework.boot.actuate.servlet.MockServletWebServerFactory;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

/**
 * Tests for {@link PublicMetricsAutoConfiguration}.
 *
 * @author Stephane Nicoll
 * @author Dave Syer
 * @author Phillip Webb
 */
public class PublicMetricsAutoConfigurationTests {

    private ConfigurableApplicationContext context;

    @After
    public void after() {
        if (this.context != null) {
            this.context.close();
        }
    }

    @Test
    public void systemPublicMetrics() throws Exception {
        load();
        assertThat(this.context.getBeansOfType(SystemPublicMetrics.class)).hasSize(1);
    }

    @Test
    public void metricReaderPublicMetrics() throws Exception {
        load();
        assertThat(this.context.getBeansOfType(MetricReaderPublicMetrics.class)).hasSize(2);
    }

    @Test
    public void richGaugePublicMetrics() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                RichGaugeReaderConfig.class, MetricRepositoryAutoConfiguration.class,
                PublicMetricsAutoConfiguration.class);
        RichGaugeReader richGaugeReader = context.getBean(RichGaugeReader.class);
        assertThat(richGaugeReader).isNotNull();
        given(richGaugeReader.findAll()).willReturn(Collections.singletonList(new RichGauge("bar", 3.7d)));
        RichGaugeReaderPublicMetrics publicMetrics = context.getBean(RichGaugeReaderPublicMetrics.class);
        assertThat(publicMetrics).isNotNull();
        Collection<Metric<?>> metrics = publicMetrics.metrics();
        assertThat(metrics).isNotNull();
        assertThat(6).isEqualTo(metrics.size());
        assertHasMetric(metrics, new Metric<>("bar.val", 3.7d));
        assertHasMetric(metrics, new Metric<>("bar.avg", 3.7d));
        assertHasMetric(metrics, new Metric<>("bar.min", 3.7d));
        assertHasMetric(metrics, new Metric<>("bar.max", 3.7d));
        assertHasMetric(metrics, new Metric<>("bar.alpha", -1.d));
        assertHasMetric(metrics, new Metric<>("bar.count", 1L));
        context.close();
    }

    @Test
    public void noDataSource() {
        load();
        assertThat(this.context.getBeansOfType(DataSourcePublicMetrics.class)).isEmpty();
    }

    @Test
    public void autoDataSource() throws SQLException {
        load(DataSourceAutoConfiguration.class);
        PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class);
        this.context.getBean(DataSource.class).getConnection().close();
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage");
    }

    @Test
    public void multipleDataSources() {
        load(MultipleDataSourcesConfig.class);
        PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class);
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "datasource.tomcat.active", "datasource.tomcat.usage",
                "datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
        // Hikari won't work unless a first connection has been retrieved
        JdbcTemplate jdbcTemplate = new JdbcTemplate(this.context.getBean("hikariDS", DataSource.class));
        jdbcTemplate.execute((ConnectionCallback<Void>) (connection) -> null);
        Collection<Metric<?>> anotherMetrics = bean.metrics();
        assertMetrics(anotherMetrics, "datasource.tomcat.active", "datasource.tomcat.usage",
                "datasource.hikariDS.active", "datasource.hikariDS.usage", "datasource.commonsDbcp.active",
                "datasource.commonsDbcp.usage");
    }

    @Test
    public void multipleDataSourcesWithPrimary() {
        load(MultipleDataSourcesWithPrimaryConfig.class);
        PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class);
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage",
                "datasource.commonsDbcp.active", "datasource.commonsDbcp.usage");
    }

    @Test
    public void multipleDataSourcesWithCustomPrimary() {
        load(MultipleDataSourcesWithCustomPrimaryConfig.class);
        PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class);
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "datasource.primary.active", "datasource.primary.usage",
                "datasource.dataSource.active", "datasource.dataSource.usage");
    }

    @Test
    public void customPrefix() {
        load(MultipleDataSourcesWithPrimaryConfig.class, CustomDataSourcePublicMetrics.class);
        PublicMetrics bean = this.context.getBean(DataSourcePublicMetrics.class);
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "ds.first.active", "ds.first.usage", "ds.second.active", "ds.second.usage");
    }

    @Test
    public void tomcatMetrics() throws Exception {
        loadWeb(TomcatConfiguration.class);
        assertThat(this.context.getBeansOfType(TomcatPublicMetrics.class)).hasSize(1);
    }

    @Test
    public void noCacheMetrics() {
        load();
        assertThat(this.context.getBeansOfType(CachePublicMetrics.class)).isEmpty();
    }

    @Test
    public void autoCacheManager() {
        load(CacheConfiguration.class);
        CachePublicMetrics bean = this.context.getBean(CachePublicMetrics.class);
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "cache.books.size", "cache.speakers.size");
    }

    @Test
    public void multipleCacheManagers() {
        load(MultipleCacheConfiguration.class);
        CachePublicMetrics bean = this.context.getBean(CachePublicMetrics.class);
        Collection<Metric<?>> metrics = bean.metrics();
        assertMetrics(metrics, "cache.books.size", "cache.second_speakers.size", "cache.first_speakers.size",
                "cache.users.size");
    }

    private void assertHasMetric(Collection<Metric<?>> metrics, Metric<?> metric) {
        for (Metric<?> m : metrics) {
            if (m.getValue().equals(metric.getValue()) && m.getName().equals(metric.getName())) {
                return;
            }
        }
        fail("Metric " + metric.toString() + " not found in " + metrics.toString());
    }

    private void assertMetrics(Collection<Metric<?>> metrics, String... keys) {
        Map<String, Number> content = new HashMap<>();
        for (Metric<?> metric : metrics) {
            content.put(metric.getName(), metric.getValue());
        }
        for (String key : keys) {
            assertThat(content).containsKey(key);
        }
    }

    private void loadWeb(Class<?>... config) {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
        if (config.length > 0) {
            context.register(config);
        }
        context.register(DataSourcePoolMetadataProvidersConfiguration.class, CacheStatisticsAutoConfiguration.class,
                PublicMetricsAutoConfiguration.class, MockServletWebServerFactory.class);
        context.refresh();
        this.context = context;
    }

    private void load(Class<?>... config) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        if (config.length > 0) {
            context.register(config);
        }
        context.register(DataSourcePoolMetadataProvidersConfiguration.class, CacheStatisticsAutoConfiguration.class,
                PublicMetricsAutoConfiguration.class);
        context.refresh();
        this.context = context;
    }

    @Configuration
    static class MultipleDataSourcesConfig {

        @Bean
        public DataSource tomcatDataSource() {
            return InitializedBuilder.create().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
        }

        @Bean
        public DataSource hikariDS() {
            return InitializedBuilder.create().type(HikariDataSource.class).build();
        }

        @Bean
        public DataSource commonsDbcpDataSource() {
            return InitializedBuilder.create().type(BasicDataSource.class).build();
        }

    }

    @Configuration
    static class MultipleDataSourcesWithPrimaryConfig {

        @Bean
        @Primary
        public DataSource myDataSource() {
            return InitializedBuilder.create().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
        }

        @Bean
        public DataSource commonsDbcpDataSource() {
            return InitializedBuilder.create().type(BasicDataSource.class).build();
        }

    }

    @Configuration
    static class MultipleDataSourcesWithCustomPrimaryConfig {

        @Bean
        @Primary
        public DataSource myDataSource() {
            return InitializedBuilder.create().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();
        }

        @Bean
        public DataSource dataSource() {
            return InitializedBuilder.create().type(BasicDataSource.class).build();
        }

    }

    @Configuration
    static class CustomDataSourcePublicMetrics {

        @Bean
        public DataSourcePublicMetrics myDataSourcePublicMetrics() {
            return new DataSourcePublicMetrics() {
                @Override
                protected String createPrefix(String dataSourceName, DataSource dataSource, boolean primary) {
                    return (primary ? "ds.first." : "ds.second");
                }
            };
        }

    }

    @Configuration
    static class RichGaugeReaderConfig {

        @Bean
        public RichGaugeReader richGaugeReader() {
            return mock(RichGaugeReader.class);
        }

    }

    @Configuration
    static class TomcatConfiguration {

        @Bean
        public TomcatServletWebServerFactory webServerFactory() {
            return new TomcatServletWebServerFactory(0);
        }

    }

    @Configuration
    static class CacheConfiguration {

        @Bean
        public CacheManager cacheManager() {
            return new ConcurrentMapCacheManager("books", "speakers");
        }

    }

    @Configuration
    static class MultipleCacheConfiguration {

        @Bean
        @Order(1)
        public CacheManager first() {
            return new ConcurrentMapCacheManager("books", "speakers");
        }

        @Bean
        @Order(2)
        public CacheManager second() {
            return new ConcurrentMapCacheManager("users", "speakers");
        }

    }

    private static class InitializedBuilder {

        public static DataSourceBuilder create() {
            return DataSourceBuilder.create().driverClassName("org.hsqldb.jdbc.JDBCDriver")
                    .url("jdbc:hsqldb:mem:test").username("sa");
        }

    }

}