/* * 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; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.ReflectionException; import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.actuate.endpoint.AbstractEndpoint; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.jmx.EndpointMBeanExporter; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableMBeanExport; import org.springframework.jmx.export.MBeanExporter; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.mock.env.MockEnvironment; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link EndpointMBeanExportAutoConfiguration}. * */ public class EndpointMBeanExportAutoConfigurationTests { private AnnotationConfigApplicationContext context; @After public void close() { if (this.context != null) { this.context.close(); } } @Test public void testEndpointMBeanExporterIsInstalled() throws Exception { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfiguration.class, JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(EndpointMBeanExporter.class)).isNotNull(); MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); assertThat(mbeanExporter.getServer() .queryNames(getObjectName("*", "*,*", this.context), null)).isNotEmpty(); } @Test public void testEndpointMBeanExporterIsNotInstalledIfManagedResource() throws Exception { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfiguration.class, JmxAutoConfiguration.class, ManagedEndpoint.class, EndpointMBeanExportAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(EndpointMBeanExporter.class)).isNotNull(); MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); assertThat(mbeanExporter.getServer() .queryNames(getObjectName("*", "*,*", this.context), null)).isEmpty(); } @Test public void testEndpointMBeanExporterIsNotInstalledIfNestedInManagedResource() throws Exception { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfiguration.class, JmxAutoConfiguration.class, NestedInManagedEndpoint.class, EndpointMBeanExportAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(EndpointMBeanExporter.class)).isNotNull(); MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); assertThat(mbeanExporter.getServer() .queryNames(getObjectName("*", "*,*", this.context), null)).isEmpty(); } @Test(expected = NoSuchBeanDefinitionException.class) public void testEndpointMBeanExporterIsNotInstalled() { MockEnvironment environment = new MockEnvironment(); environment.setProperty("endpoints.jmx.enabled", "false"); this.context = new AnnotationConfigApplicationContext(); this.context.setEnvironment(environment); this.context.register(JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); this.context.refresh(); this.context.getBean(EndpointMBeanExporter.class); } @Test public void testEndpointMBeanExporterWithProperties() throws IntrospectionException, InstanceNotFoundException, MalformedObjectNameException, ReflectionException { MockEnvironment environment = new MockEnvironment(); environment.setProperty("endpoints.jmx.domain", "test-domain"); environment.setProperty("endpoints.jmx.unique_names", "true"); environment.setProperty("endpoints.jmx.static_names", "key1=value1, key2=value2"); this.context = new AnnotationConfigApplicationContext(); this.context.setEnvironment(environment); this.context.register(JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); this.context.refresh(); this.context.getBean(EndpointMBeanExporter.class); MBeanExporter mbeanExporter = this.context.getBean(EndpointMBeanExporter.class); assertThat(mbeanExporter.getServer().getMBeanInfo(ObjectNameManager.getInstance( getObjectName("test-domain", "healthEndpoint", this.context).toString() + ",key1=value1,key2=value2"))).isNotNull(); } @Test public void testEndpointMBeanExporterInParentChild() throws IntrospectionException, InstanceNotFoundException, MalformedObjectNameException, ReflectionException { this.context = new AnnotationConfigApplicationContext(); this.context.register(JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); parent.register(JmxAutoConfiguration.class, EndpointAutoConfiguration.class, EndpointMBeanExportAutoConfiguration.class); this.context.setParent(parent); parent.refresh(); this.context.refresh(); parent.close(); } private ObjectName getObjectName(String domain, String beanKey, ApplicationContext applicationContext) throws MalformedObjectNameException { String name = "%s:type=Endpoint,name=%s"; if (applicationContext.getParent() != null) { name = name + ",context=%s"; } if (applicationContext.getEnvironment().getProperty("endpoints.jmx.unique_names", Boolean.class, false)) { name = name + ",identity=" + ObjectUtils .getIdentityHexString(applicationContext.getBean(beanKey)); } if (applicationContext.getParent() != null) { return ObjectNameManager.getInstance(String.format(name, domain, beanKey, ObjectUtils.getIdentityHexString(applicationContext))); } return ObjectNameManager.getInstance(String.format(name, domain, beanKey)); } @Configuration @EnableMBeanExport public static class TestConfiguration { } @Component @ManagedResource public static class ManagedEndpoint extends AbstractEndpoint<Boolean> { public ManagedEndpoint() { super("managed", true); } @Override public Boolean invoke() { return true; } } @Configuration @ManagedResource public static class NestedInManagedEndpoint { @Bean public Endpoint<Boolean> nested() { return new Nested(); } class Nested extends AbstractEndpoint<Boolean> { Nested() { super("managed", true); } @Override public Boolean invoke() { return true; } } } }