/*
* 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;
}
}
}
}